예제 #1
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (_hasViewChanged)
            {
                // In determining the labels to display, it must be kept in mind that the spacings between
                // the labels might be variable depending on the current time unit. For instance, if the
                // timeline is measured in months, then the labels will not be equally spaced apart because
                // a month is anywhere from 28 to 31 days. The solution is to produce labels one at a time
                // while the total accumulated width is less than the viewport width.
                //
                // 1. First we first convert the current horizontal offset into a TimeSpan, and add
                // that to the timeline's start time to get the time of the viewport's left edge. This
                // time may be more precise than the timeline's current unit of measurement. For
                // example, the viewport left time may be defined down to the second, but the timeline's
                // unit is an hour. Therefore, we must round up to the nearest unit.
                //
                // 2. The difference between the rounded date and the precise date is the time between
                // the start of the viewport and the initial label. Converting this TimeSpan into pixels
                // will yield the x position of the initial label relative to the viewport's left edge.
                // We can store this value along with the label number for use during the arranging process.
                //
                // 3. Now we can create a label, add it to the panel, and measure it.
                //
                // 4. Next we increment the rounded date by whatever is set as the timeline's unit.
                //
                // 5. Repeat steps 2 to 4 until the rounded date is equal to or exceeds the date of the
                // viewport's right edge.

                Children.Clear();

                if (_labelOffsets == null)
                {
                    _labelOffsets = new Dictionary<int, double>();
                }
                else
                {
                    _labelOffsets.Clear();
                }

                ExtendedDateTime viewportLeftTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset);
                ExtendedDateTime viewportRightTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset + availableSize.Width);
                ExtendedDateTime labelTime = null;
                int labelIndex = 0;

                switch (Resolution)
                {
                    case TimeResolution.Century:
                        labelTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 100);
                        break;

                    case TimeResolution.Decade:
                        labelTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 10);
                        break;

                    case TimeResolution.Year:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Year);
                        break;

                    case TimeResolution.Month:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Month, false);
                        break;

                    case TimeResolution.Day:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Day, false);
                        break;

                    case TimeResolution.Hour:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Hour, false);
                        break;

                    case TimeResolution.Minute:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Minute, false);
                        break;

                    case TimeResolution.Second:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Second, false);
                        break;

                    default:
                        break;
                }

                while (labelTime < viewportRightTime)
                {
                    var label = new TextBlock();
                    label.Text = labelTime.ToString();
                    label.FontFamily = FontFamily;
                    label.FontSize = FontSize;
                    label.Foreground = Foreground;

                    switch (Resolution)
                    {
                        case TimeResolution.Century:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddYears(100);
                            break;

                        case TimeResolution.Decade:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddYears(10);
                            break;

                        case TimeResolution.Year:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddYears(1);
                            break;

                        case TimeResolution.Month:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddMonths(1);
                            break;

                        case TimeResolution.Day:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromDays(1);
                            break;

                        case TimeResolution.Hour:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromHours(1);
                            break;

                        case TimeResolution.Minute:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromMinutes(1);
                            break;

                        case TimeResolution.Second:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromSeconds(1);
                            break;

                        default:
                            break;
                    }

                    Children.Add(label);
                    label.Measure(availableSize);

                    labelIndex++;
                }

                _hasViewChanged = false;

                return availableSize;
            }

            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
            }

            return availableSize;
        }
예제 #2
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (_hasViewChanged)
            {
                // In determining the number of guidelines to display, it must be kept in mind that
                // the spacings between the lines might be variable depending on the
                // current time unit. For instance, if the timeline is measured in months, then the
                // lines will not be equally spaced apart because a month is anywhere from 28 to 31 days.
                // The solution is to produce lines one at a time while the total accumulated width is
                // less than the viewport width.
                //
                // 1. First we first convert the current horizontal offset into a TimeSpan, and add
                // that to the timeline's start time to get the time of the viewport's left edge. This
                // time may be more precise than the timeline's current unit of measurement. For
                // example, the viewport left time may be defined down to the second, but the timeline's
                // unit is an hour. Therefore, we must round up to the nearest unit.
                //
                // 2. The difference between the rounded date and the precise date is the time between
                // the start of the viewport and the initial line. Converting this TimeSpan into pixels
                // will yield the x position of the initial line relative to the viewport's left edge.
                // We can store this value along with the line number for use during the arranging process.
                //
                // 3. Now we can create a guideline, add it to the panel, and measure it.
                //
                // 4. Next we increment the rounded date by whatever is set as the timeline's unit.
                //
                // 5. Repeat steps 2 to 4 until the rounded date is equal to or exceeds the date of the
                // viewport's right edge.

                Children.Clear();

                if (_lineOffsets == null)
                {
                    _lineOffsets = new Dictionary<int, double>();
                }
                else
                {
                    _lineOffsets.Clear();
                }

                ExtendedDateTime viewportLeftTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset);
                ExtendedDateTime viewportRightTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset + availableSize.Width);
                ExtendedDateTime guidelineTime = null;
                int guidelineIndex = 0;

                switch (Resolution)
                {
                    case TimeResolution.Century:
                        guidelineTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 100 + 100);
                        break;

                    case TimeResolution.Decade:
                        guidelineTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 10 + 10);
                        break;

                    case TimeResolution.Year:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Year, true);
                        break;

                    case TimeResolution.Month:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Month, true);
                        break;

                    case TimeResolution.Day:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Day, true);
                        break;

                    case TimeResolution.Hour:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Hour, true);
                        break;

                    case TimeResolution.Minute:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Minute, true);
                        break;

                    case TimeResolution.Second:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Second, true);
                        break;

                    default:
                        break;
                }

                while (guidelineTime < viewportRightTime)
                {
                    var guideline = new Line();
                    guideline.Y2 = availableSize.Height;
                    guideline.StrokeThickness = 1;
                    guideline.UseLayoutRounding = true;
                    guideline.SnapsToDevicePixels = true;

                    switch (Resolution)
                    {
                        case TimeResolution.Century:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Year % (100 * MajorFrequency) == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime.AddYears(100);
                            break;

                        case TimeResolution.Decade:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Year % (10 * MajorFrequency) == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime.AddYears(10);
                            break;

                        case TimeResolution.Year:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Year % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime.AddYears(1);
                            break;

                        case TimeResolution.Month:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Month % MajorFrequency == 0 ? MajorBrush : MinorBrush;

                            try
                            {
                                guidelineTime = guidelineTime.AddMonths(1);
                            }
                            catch (Exception)
                            {
                                var month = guidelineTime.Month + 1;
                                var year = guidelineTime.Year;

                                if (month > 12)
                                {
                                    month -= 12;
                                    year++;
                                }

                                var day = ExtendedDateTimeCalculator.DaysInMonth(year, month);

                                guidelineTime = new ExtendedDateTime(year, month, day, guidelineTime.Hour, guidelineTime.Minute, guidelineTime.Second, guidelineTime.UtcOffset.Hours, guidelineTime.UtcOffset.Minutes);
                            }

                            break;

                        case TimeResolution.Day:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Day % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromDays(1);
                            break;

                        case TimeResolution.Hour:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Hour % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromHours(1);
                            break;

                        case TimeResolution.Minute:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Minute % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromMinutes(1);
                            break;

                        case TimeResolution.Second:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Second % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromSeconds(1);
                            break;

                        default:
                            break;
                    }

                    Children.Add(guideline);
                    guideline.Measure(availableSize);

                    guidelineIndex++;
                }

                _hasViewChanged = false;

                return availableSize;
            }

            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
            }

            return availableSize;
        }