/// <summary>
 /// 筛选出没有在当前 RectanglesCanvas 面板中显示的、日期更久远的记录,
 /// 然后根据这些记录在 StackCanvas 面板中生成新的方块面板,接着在这些
 /// 新生成的面板中着色日期更久远的记录。
 /// </summary>
 private void ExtendStackCanvasByFilterOldRecorders(List <StatistTotalByDateTime> oldRecorders, Rectangle earliestRectangle, int canvasOrdinal = 1)
 {
     if (oldRecorders != null && oldRecorders.Count > 0)
     {
         Canvas oldRectanglesCanvas = new Canvas()
         {
             Name = $"OldRectanglesCanvas_{canvasOrdinal}"
         };
         Rectangle oldRect = this.RectanglesLayout(oldRectanglesCanvas, DatetimeParser.ParseExpressToDateTime(earliestRectangle.Name, DateMode.DateWithSlash).AddDays(-1));
         oldRectanglesCanvas.Loaded += (object sender, RoutedEventArgs e) => {
             Canvas canvas = sender as Canvas;
             foreach (var item in canvas.Children)
             {
                 if (item is TextBlock tag)
                 {
                     Debug.WriteLine($"tag.ActualWidth: {tag.ActualWidth}");
                 }
             }
         };
         this.StackCanvas.Children.Insert(0, oldRectanglesCanvas);
         List <StatistTotalByDateTime> newOldRecorders = EarlierThanEarliestRectangle(oldRecorders, oldRect);
         ExtendStackCanvasByFilterOldRecorders(newOldRecorders, oldRect, canvasOrdinal + 1);
     }
     // 扩展结束后,给每个 RectanglesCanvas 附加进度条
     else
     {
         foreach (Canvas canvas in this.StackCanvas.Children)
         {
             ProgressBoard.SlideOn(canvas, new ProgressBoard());
         }
     }
 }
示例#2
0
 /// <summary>
 /// 该构造器接收一个字符串序列,把它转换成StatistTotalByDateTime链表,同时接收一个 DateMode 指示日期字符串的分割方式
 /// </summary>
 /// <param name="lines">文本序列</param>
 /// <param name="dateMode">指示日期字符串的分割方式</param>
 public StatistTotalByDateTimeModel(IEnumerable <string> lines, DateMode dateMode)
 {
     foreach (var line in lines)
     {
         if (line != "" && line != "\r")     // 忽略空行
         {
             StatistTotalByDateTime statist = DatetimeParser.ParseExpressToStatistTotalByDateTime(line, dateMode);
             this.Add(statist);
         }
     }
 }
        /// <summary>
        /// 返回所有的事件记录中含有比 rect 的日期还要早的记录。
        /// </summary>
        /// <param name="entries">存储事件链的模型类</param>
        /// <param name="rect">用于日期比较的目标方块</param>
        /// <returns></returns>
        private static List <StatistTotalByDateTime> EarlierThanEarliestRectangle(List <StatistTotalByDateTime> entries, Rectangle rect)
        {
            List <StatistTotalByDateTime> earlierThanEarliestRectangleLik = new List <StatistTotalByDateTime>();

            foreach (var item in entries)
            {
                if (item.DateTime < DatetimeParser.ParseExpressToDateTime(rect.Name, DateMode.DateWithSlash))
                {
                    earlierThanEarliestRectangleLik.Add(item);
                }
            }
            return(earlierThanEarliestRectangleLik);
        }
        private static async Task <StatistTotalByDateTimeModel> EncodingToStatistTotalByDateTimeModelAsync(StorageFile file)
        {
            string text = await FileIO.ReadTextAsync(file);

            if (file.FileType == ".txt")
            {
                IEnumerable <string> lines = DatetimeParser.SplitByLine(text);
                return(new StatistTotalByDateTimeModel(lines));
            }
            else if (file.FileType == ".mast")
            {
                JymlAST.Cons ast = JymlParser.Parser.GenerateAst(text);
                Interpreter.SuckerMLInterpreter.Sucker sucker = Interpreter.SuckerMLInterpreter.Eval(ast);
                List <StatistTotalByDateTime>          statistTotalByDateTimes = new List <StatistTotalByDateTime>();
                foreach (var year in sucker.Years)
                {
                    foreach (var month in year.Value.Months)
                    {
                        foreach (var day in month.Value.Days)
                        {
                            statistTotalByDateTimes.Add(new StatistTotalByDateTime()
                            {
                                DateTime = new DateTime(
                                    year: year.Value.Year.BigIntegerToInt32(),
                                    month: month.Value.Month,
                                    day: day.Value.Day
                                    ),
                                Total = day.Value.Total
                            });
                        }
                    }
                }
                return(new StatistTotalByDateTimeModel(statistTotalByDateTimes));
            }
            else
            {
                throw new FilePickFaildException($"错误的文件类型:{_file.FileType}");
            }
        }
        /// <summary>
        /// 给相应的 Rectangle 标记上日期和星期数
        /// </summary>
        /// <param name="canvas"></param>
        private static void DateTag(Canvas canvas)
        {
            /*
             * 下面的查询语句用来提取画布中最左侧的一列方块(res1)和最上侧的一行方块(res2),
             * 然后将这些方块标记上星期数和月份
             */
            IEnumerable <IGrouping <double, UIElement> > leftGroup = from rect in canvas.Children
                                                                     group rect by Canvas.GetLeft(rect);

            IEnumerable <IGrouping <double, UIElement> > topGroup = from rect in canvas.Children
                                                                    group rect by Canvas.GetTop(rect);

            double minLeftGroupKey             = leftGroup.Min(group => group.Key);
            double minTopGroupKey              = topGroup.Min(group => group.Key);
            IGrouping <double, UIElement> res1 = (from g in leftGroup
                                                  where g.Key == minLeftGroupKey
                                                  select g).First();
            IGrouping <double, UIElement> res2 = (from g in topGroup
                                                  where g.Key == minTopGroupKey
                                                  select g).First();

            /*
             * 给周一、周三、周五的方块打上标记 Mon、Wed、Fri
             */
            foreach (Rectangle rect in res1)
            {
                if (DatetimeParser.ParseExpressToDateTime((rect as Rectangle).Name, DateMode.DateWithSlash).DayOfWeek == DayOfWeek.Monday ||
                    DatetimeParser.ParseExpressToDateTime((rect as Rectangle).Name, DateMode.DateWithSlash).DayOfWeek == DayOfWeek.Wednesday ||
                    DatetimeParser.ParseExpressToDateTime((rect as Rectangle).Name, DateMode.DateWithSlash).DayOfWeek == DayOfWeek.Friday)
                {
                    var tbx = new TextBlock()
                    {
                        Text       = DatetimeParser.ParseExpressToDateTime((rect as Rectangle).Name, DateMode.DateWithSlash).DayOfWeek.ToString().Substring(0, 3),
                        FontSize   = 10,
                        Foreground = new SolidColorBrush(Windows.UI.Colors.Gray)
                    };
                    Canvas.SetLeft(tbx, Canvas.GetLeft(rect) - 30);
                    Canvas.SetTop(tbx, Canvas.GetTop(rect));
                    canvas.Children.Add(tbx);
                }
            }

            /*
             * 给每个月份开头的方块打上标记,从 Jan 到 Dec
             */
            Rectangle previousRect = null;
            // 每个标记创建完成后会同对应的方块一起写入该列表
            List <(TextBlock Tag, Rectangle TagedRect)> tagList = new List <(TextBlock Tag, Rectangle TagedRect)>();

            foreach (Rectangle rect in res2.Reverse())
            {
                void setTopTag(string text)
                {
                    var tag = new TextBlock()
                    {
                        Text       = text,
                        FontSize   = 10,
                        Foreground = new SolidColorBrush(Windows.UI.Colors.Gray)
                    };

                    Canvas.SetLeft(tag, Canvas.GetLeft(rect));
                    Canvas.SetTop(tag, Canvas.GetTop(rect) - 15);
                    tagList.Add((tag, rect));

                    /*
                     * 采用下面的设计是因为 TextBlock.ActualWidth 只有在控件加载完成后(Loaded)才会产生有效值,
                     * TextBlock.ActualWidth 是检测两个 tag 是否重叠的关键参数,检测公式为:
                     * Canvas.GetLeft(tagList[i].Tag) - Canvas.GetLeft(tagList[i - 1].Tag) - tagList[i - 1].Tag.ActualWidth <= 0
                     * 当该表达式为 true,表明 tagList 中某两个相邻的 tag 发生重叠,需要将右边的 tag 往右移动一个方块的距离避免重叠。
                     * 当 today 为一年中的某些天时,RectanglesCanvas 的第一列和第二列会是两个相邻的月份,如此紧凑的距离会导致他们顶部
                     * 的标记重叠,一个例子是 today 为 10/12/2019,当输入的纪录中含有 2017 年的记录时,那么渲染 2017 年对应的 RectanglesCanvas
                     * 会导致该 Canvas 的第一列和第二列的顶部标记重叠。
                     *
                     * tag.Loaded 事件函数的作用是对 tagList 中的 tag 进行距离检测,当所有的 tag 在 setTopTag 函数中
                     * 创建完毕后,UI 开始加载 Canvas 中的 UIElement,这个过程会触发每个 tag 的 Loaded 事件,通过 Loaded
                     * 事件对每个 tag 的距离进行轮询。
                     */
                    tag.Loaded += (object sender, RoutedEventArgs e) => {
                        for (int i = 1; i < tagList.Count - 1; i++)
                        {
                            if (Canvas.GetLeft(tagList[i].Tag) - Canvas.GetLeft(tagList[i - 1].Tag) - tagList[i - 1].Tag.ActualWidth <= 0)
                            {
                                Debug.WriteLine($"Canvas.GetLeft(list[{i}].Tag) - Canvas.GetLeft(list[{i - 1}].Tag) - list[{i - 1}].Tag.ActualWidth = {Canvas.GetLeft(tagList[i].Tag)} - {Canvas.GetLeft(tagList[i - 1].Tag)} - {tagList[i - 1].Tag.ActualWidth} = {Canvas.GetLeft(tagList[i].Tag) - Canvas.GetLeft(tagList[i - 1].Tag) - tagList[i - 1].Tag.ActualWidth}");
                                Canvas.SetLeft(tagList[i].Tag, Canvas.GetLeft(tagList[i].Tag) + tagList[i].TagedRect.Width);
                            }
                        }
                    };
                    canvas.Children.Add(tag);
                }

                if (previousRect == null)
                {
                    setTopTag(DatetimeParser.NumberToMonth(DatetimeParser.ParseExpressToDateTime(rect.Name, DateMode.DateWithSlash).Month));
                }
                else
                {
                    int monthOfPreviousRectangle = DatetimeParser.ParseExpressToDateTime(previousRect.Name, DateMode.DateWithSlash).Month;
                    int monthOfCurrentRectangle  = DatetimeParser.ParseExpressToDateTime(rect.Name, DateMode.DateWithSlash).Month;
                    if (monthOfCurrentRectangle != monthOfPreviousRectangle)
                    {
                        setTopTag(DatetimeParser.NumberToMonth(DatetimeParser.ParseExpressToDateTime(rect.Name, DateMode.DateWithSlash).Month));
                    }
                }
                previousRect = rect;
            }
        }
示例#6
0
 /// <summary>
 /// 添加一个条目
 /// </summary>
 /// <param name="rectName">接收一个字符串表达式,格式为“mm dd yyyy x{Total}”或“mm/dd/yyyy”</param>
 public void AddEntry(string rectName)
 {
     this.AddEntry(DatetimeParser.ParseExpressToStatistTotalByDateTime(rectName, DateMode.DateWithSlash));
 }