Пример #1
0
        /// <summary>
        /// Raises the <see cref="ChartElement.Updated"/> event.
        /// </summary>
        /// <remarks>
        /// <strong>Notes to Inheritors:</strong> When overriding <see cref="OnUpdate"/> in a
        /// derived class, be sure to call the base class's <see cref="OnUpdate"/> method so that
        /// the base class <see cref="Chart"/> can update the data source if required.
        /// </remarks>
        protected override void OnUpdate()
        {
            base.OnUpdate();  // Updates the data source, if required.

            // Cleanup
            _lineRenderer.Clear();
            _areaRenderer.Clear();

            Debug.Assert(Canvas.Children.Count == 0, "Canvas should be cleared in base class.");
            Canvas.Children.Add(_areaPath);
            Canvas.Children.Add(_linePath);

            if (Data != null && Data.Count != 0)
            {
                // Clip filled area and lines to the chart area.
                Rect chartArea = ChartPanel.GetChartAreaBounds(XAxis, YAxis);

                // Allow line to draw on chart axes.
                Rect lineClipRect = new Rect(chartArea.Left - 2, chartArea.Top - 2, chartArea.Width + 4, chartArea.Height + 4);
                LineClipGeometry = new RectangleGeometry { Rect = lineClipRect };

                // Keep area inside the chart area.
                Rect areaClipRect = chartArea;
                AreaClipGeometry = new RectangleGeometry { Rect = areaClipRect };

                FindVisibleDataPoints();
                CachePositions();


                OnUpdateLines(_startIndex, _endIndexExclusive, _xPositions, _basePositions, _yPositions);
                UpdateMarkers();
#else
                switch (RenderMode)
                {
                    case ChartRenderMode.Quality:
                        // Update lines and markers immediately.
                        OnUpdateLines(_startIndex, _endIndexExclusive, _xPositions, _basePositions, _yPositions);
                        UpdateMarkers();
                        break;

                    case ChartRenderMode.Performance:
                        // Immediately update lines.
                        OnUpdateLines(_startIndex, _endIndexExclusive, _xPositions, _basePositions, _yPositions);

                        // Temporarily disable bitmap cache and anti-aliasing.
                        // Update markers when application is idle.
                        if (!_updatePending)
                        {
                            _updatePending = true;
                            ClearCacheMode();
                            ClearEdgeMode();
                            ChartHelper.Defer(Dispatcher, () =>
                            {
                                if (_updatePending)
                                {
                                    _updatePending = false;
                                    UpdateMarkers();
                                    RestoreCacheMode();
                                    RestoreEdgeMode();
                                }
                            });
                        }
                        break;

                    case ChartRenderMode.DoNotRender:
                        // Do nothing.
                        break;
                }

            }
        }
Пример #2
0
        /// <inheritdoc/>
        protected override void OnUpdate()
        {
            base.OnUpdate();

            Debug.Assert(Canvas.Children.Count == 0, "Canvas should be cleared in base class.");

            if (Data == null || Data.Count == 0 || DataPointTemplate == null)
            {
                // A relevant property is not set.
                return;
            }

            // Fetch dependency properties. (Accessing dependency properties is expensive.)
            Axis xAxis = XAxis;
            Axis yAxis = YAxis;
            AxisScale xScale = xAxis.Scale;
            AxisScale yScale = yAxis.Scale;

            double centerX = CenterX;
            double centerY = CenterY;
            double hole = Hole;
            double outerRadius = Radius;
            Thickness padding = Padding;

            if (hole < 0 || hole > 1)
                throw new ChartException("Pie chart has invalid hole size. The hole size is relative to the outer radius and must be in the range [0, 1].");
            if (outerRadius < 0)
                throw new ChartException("Pie chart has invalid radius. The radius must be a equal to or greater than 0.");

            // Determine available space.
            double left = xAxis.GetPosition(xScale.Min);
            double right = xAxis.GetPosition(xScale.Max);
            if (left > right)
            {
                // Scale is reversed.
                ChartHelper.Swap(ref left, ref right);
            }

            double top = yAxis.GetPosition(yScale.Max);
            double bottom = yAxis.GetPosition(yScale.Min);
            if (top > bottom)
            {
                // Scale is reversed.
                ChartHelper.Swap(ref top, ref bottom);
            }

            // Apply padding.
            left += padding.Left;
            right -= padding.Right;
            top += padding.Top;
            bottom -= padding.Bottom;

            if (Numeric.IsNaN(centerX))
            {
                // Center pie chart horizontally.
                centerX = (left + right) / 2;
            }
            else
            {
                centerX = xAxis.OriginX + centerX * xAxis.Length;
            }

            if (Numeric.IsNaN(centerY))
            {
                // Center pie chart vertically.
                centerY = (top + bottom) / 2;
            }
            else
            {
                centerY = yAxis.OriginY - (1.0 - centerY) * yAxis.Length;
            }

            if (Numeric.IsNaN(outerRadius))
            {
                // Fit pie chart into available space.
                double radiusLeft = centerX - left;
                double radiusRight = right - centerX;
                double radiusTop = centerY - top;
                double radiusBottom = bottom - centerY;

                outerRadius = radiusLeft;
                if (outerRadius > radiusRight)
                    outerRadius = radiusRight;
                if (outerRadius > radiusTop)
                    outerRadius = radiusTop;
                if (outerRadius > radiusBottom)
                    outerRadius = radiusBottom;
            }

            if (Numeric.IsNaN(hole))
                hole = 0;

            double innerRadius = hole * outerRadius;
            ActualHoleRadius = innerRadius;

            // Draw pie chart inside chart panel.
            DrawPieChart(Canvas, centerX, centerY, innerRadius, outerRadius, BrushSelector, false);

            // Update legend symbols inside legends.
            // Use a fixed innerRadius
            innerRadius = (Hole > 0) ? 2 : 0;
            foreach (var legendSymbol in _legendSymbols)
                DrawPieChart(legendSymbol, 8, 8, innerRadius, 8, BrushSelector, true);
        }
Пример #3
0
        private void GetBrushes(double paletteIndex, out Brush strokeBrush, out Brush fillBrush)
        {
            Axis xAxis = XAxis;
            Axis yAxis = YAxis;

            strokeBrush = null;
            fillBrush = null;

            if (FillMode == BarFillMode.Solid)
            {
                // Solid:
                // Get a solid color brush for fill and stroke.
                if (FillPalette != null && FillPalette.Count > 0)
                    fillBrush = new SolidColorBrush(FillPalette.GetColor(paletteIndex));

                if (StrokePalette != null && StrokePalette.Count > 0)
                    strokeBrush = new SolidColorBrush(StrokePalette.GetColor(paletteIndex));
            }
            else
            {
                // Gradient:
                // We draw from 0 upwards or from a negative value upwards to 0.
                double lower = Math.Min(0, paletteIndex);
                double higher = Math.Max(0, paletteIndex);

                // Define end point for gradient direction.
                Point startPoint;
                Point endPoint;
                if (PaletteIndex == PaletteIndex.XValue)
                {
                    // Horizontal
                    startPoint = new Point(0, 0);
                    endPoint = new Point(1, 0);
                    if (xAxis != null && xAxis.Scale != null && xAxis.Scale.Reversed)
                        ChartHelper.Swap(ref startPoint, ref endPoint);
                }
                else
                {
                    // Vertical
                    startPoint = new Point(0, 1);
                    endPoint = new Point(0, 0);
                    if (yAxis != null && yAxis.Scale != null && yAxis.Scale.Reversed)
                        ChartHelper.Swap(ref startPoint, ref endPoint);
                }

                // Get brush for fill and stroke.
                if (FillPalette != null && FillPalette.Count > 0)
                {
                    fillBrush = new LinearGradientBrush
                    {
                        GradientStops = FillPalette.GetGradient(lower, higher),
                        StartPoint = startPoint,
                        EndPoint = endPoint,
                        ColorInterpolationMode = FillPalette.ColorInterpolationMode
                    };
                }

                if (StrokePalette != null && StrokePalette.Count > 0)
                {
                    strokeBrush = new LinearGradientBrush
                    {
                        GradientStops = StrokePalette.GetGradient(lower, higher),
                        StartPoint = startPoint,
                        EndPoint = endPoint,
                        ColorInterpolationMode = StrokePalette.ColorInterpolationMode
                    };
                }
            }
        }
Пример #4
0
        protected override Size ArrangeOverride(Size finalSize)
        {
            // Ensure that all axes are up to date.
            foreach (Axis axis in _monitoredAxes)
                axis.Update();

            UIElementCollection children = Children;
            for (int i = 0; i < children.Count; ++i)
            {
                UIElement child = children[i];
                if (child == null)
                    continue;

                // Get the child or one of its descendants that needs to be positioned.
                DependencyObject elementThatRequiresArrange = GetElementThatRequiresArrange(child);
                if (elementThatRequiresArrange == null)
                {
                    // This child ignores the attached properties (X1, Y1, X2, Y2).
                    Rect childBounds = new Rect(new Point(), finalSize);

                    // Arrange element,
                    child.Arrange(childBounds);

                    // Clip to chart area.
                    if (GetClipToChartArea(child))
                        ClipElementToChartArea(child, childBounds);
                }
                else
                {
                    // Determine alignment.
                    HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left;
                    VerticalAlignment verticalAlignment = VerticalAlignment.Top;
                    if (elementThatRequiresArrange is FrameworkElement)
                    {
                        FrameworkElement frameworkElement = (FrameworkElement)elementThatRequiresArrange;
                        horizontalAlignment = frameworkElement.HorizontalAlignment;
                        verticalAlignment = frameworkElement.VerticalAlignment;
                    }

                    // Get associated axes.
                    Axis xAxis = GetXAxis(elementThatRequiresArrange);
                    Axis yAxis = GetYAxis(elementThatRequiresArrange);

                    // Check whether we have to position the element relative to a point (X1, Y1) 
                    // or inside a region (X1, Y1) - (X2, Y2).
                    // Convert positions given in data values to pixel positions. 
                    double x1 = xAxis.GetPosition(GetX1(elementThatRequiresArrange));
                    double y1 = yAxis.GetPosition(GetY1(elementThatRequiresArrange));
                    double x2 = xAxis.GetPosition(GetX2(elementThatRequiresArrange));
                    double y2 = yAxis.GetPosition(GetY2(elementThatRequiresArrange));

                    bool isX1Valid = Numeric.IsFinite(x1);
                    bool isY1Valid = Numeric.IsFinite(y1);
                    bool isX2Valid = Numeric.IsFinite(x2);
                    bool isY2Valid = Numeric.IsFinite(y2);

                    double availableWidth = Double.PositiveInfinity;
                    double availableHeight = Double.PositiveInfinity;

                    if (!isX1Valid && !isX2Valid)
                    {
                        // No coordinates set. Use 0 and 'left' alignment.
                        x1 = 0;
                        x2 = Double.NaN;
                        horizontalAlignment = HorizontalAlignment.Left;
                    }
                    else if (!isX1Valid)
                    {
                        // Only X2 set. Use X2 as position.
                        x1 = x2;
                        x2 = Double.NaN;
                    }
                    else if (isX2Valid)
                    {
                        // X1 and X2 are set.
                        int result = Numeric.Compare(x1, x2);
                        if (result < 0)
                        {
                            // X1 < X2: Horizontal region.
                            availableWidth = x2 - x1;
                        }
                        else if (result == 0)
                        {
                            // X1 == X2: Use only X1.
                            x2 = Double.NaN;
                        }
                        else
                        {
                            // X2 > X1: Horizontal region, but swapped.
                            ChartHelper.Swap(ref x1, ref x2);
                            availableWidth = x2 - x1;
                        }
                    }

                    if (!isY1Valid && !isY2Valid)
                    {
                        // No coordinates set. Use 0 and 'top' alignment.
                        y1 = 0;
                        y2 = Double.NaN;
                        verticalAlignment = VerticalAlignment.Top;
                    }
                    else if (!isY1Valid)
                    {
                        // Only Y2 set. Use Y2 as position.
                        y1 = y2;
                        y2 = Double.NaN;
                    }
                    else if (isY2Valid)
                    {
                        // Y1 and Y2 are set.
                        int result = Numeric.Compare(y1, y2);
                        if (result < 0)
                        {
                            // Y1 < Y2: Horizontal region.
                            availableHeight = y2 - y1;
                        }
                        else if (result == 0)
                        {
                            // Y1 == Y2: Use only Y1.
                            y2 = Double.NaN;
                        }
                        else
                        {
                            // Y2 > Y1: Horizontal region, but swapped.
                            ChartHelper.Swap(ref y1, ref y2);
                            availableHeight = y2 - y1;
                        }
                    }

                    // Get size of child.
                    double elementWidth = child.DesiredSize.Width;
                    double elementHeight = child.DesiredSize.Height;

                    if (elementWidth == 0.0 && elementHeight == 0.0 && child is FrameworkElement)
                    {
                        // Fix for Silverlight.
                        FrameworkElement frameworkElement = (FrameworkElement)child;
                        elementWidth = frameworkElement.ActualWidth;
                        elementHeight = frameworkElement.ActualHeight;
                    }

                    // Compute bounds of the child element.
                    Rect childBounds = new Rect();

                    // Position child horizontally.
                    if (Numeric.IsNaN(x2))
                    {
                        // Position child relative to point.
                        switch (horizontalAlignment)
                        {
                            case HorizontalAlignment.Left:
                            case HorizontalAlignment.Stretch:
                                childBounds.X = x1;
                                childBounds.Width = elementWidth;
                                break;
                            case HorizontalAlignment.Center:
                                childBounds.X = x1 - elementWidth / 2.0;
                                childBounds.Width = elementWidth;
                                break;
                            case HorizontalAlignment.Right:
                                childBounds.X = x1 - elementWidth;
                                childBounds.Width = elementWidth;
                                break;
                        }
                    }
                    else
                    {
                        // Position child inside horizontal region.
                        switch (horizontalAlignment)
                        {
                            case HorizontalAlignment.Left:
                                childBounds.X = x1;
                                childBounds.Width = elementWidth;
                                break;
                            case HorizontalAlignment.Center:
                                childBounds.X = x1 + availableWidth / 2.0 - elementWidth / 2.0;
                                childBounds.Width = elementWidth;
                                break;
                            case HorizontalAlignment.Right:
                                childBounds.X = x2 - elementWidth;
                                childBounds.Width = elementWidth;
                                break;
                            case HorizontalAlignment.Stretch:
                                childBounds.X = x1;
                                childBounds.Width = availableWidth;
                                break;
                        }
                    }

                    // Position child vertically.
                    if (Numeric.IsNaN(y2))
                    {
                        // Position child relative to point.
                        switch (verticalAlignment)
                        {
                            case VerticalAlignment.Top:
                            case VerticalAlignment.Stretch:
                                childBounds.Y = y1;
                                childBounds.Height = elementHeight;
                                break;
                            case VerticalAlignment.Center:
                                childBounds.Y = y1 - elementHeight / 2.0;
                                childBounds.Height = elementHeight;
                                break;
                            case VerticalAlignment.Bottom:
                                childBounds.Y = y1 - elementHeight;
                                childBounds.Height = elementHeight;
                                break;
                        }
                    }
                    else
                    {
                        // Position child inside vertical region.
                        switch (verticalAlignment)
                        {
                            case VerticalAlignment.Top:
                                childBounds.Y = y1;
                                childBounds.Height = elementHeight;
                                break;
                            case VerticalAlignment.Center:
                                childBounds.Y = y1 + availableHeight / 2.0 - elementHeight / 2.0;
                                childBounds.Height = elementHeight;
                                break;
                            case VerticalAlignment.Bottom:
                                childBounds.Y = y2 - elementHeight;
                                childBounds.Height = elementHeight;
                                break;
                            case VerticalAlignment.Stretch:
                                childBounds.Y = y1;
                                childBounds.Height = availableHeight;
                                break;
                        }
                    }

                    // Arrange element.
                    child.Arrange(childBounds);

                    // Clip to chart area.
                    if (elementThatRequiresArrange is UIElement && GetClipToChartArea(elementThatRequiresArrange))
                    {
                        UIElement element = (UIElement)elementThatRequiresArrange;
                        ClipElementToChartArea(element, childBounds);
                    }
                }
            }

            return finalSize;
        }
Пример #5
0
        protected virtual void OnGetStrokeAndFillForLegendSymbol(double paletteIndex, out Brush stroke, out Brush fill)
        {
            Axis xAxis = XAxis;
            Axis yAxis = YAxis;

            // Check coloring parameters.
            if (PaletteIndex == PaletteIndex.Index && FillMode == AreaFillMode.GradientVertical
                || PaletteIndex == PaletteIndex.XValue && FillMode == AreaFillMode.GradientVertical)
                throw new NotSupportedException("Vertical gradients are only supported if the palette is indexed by y values.");

            // Set default values for stroke and fill brush.
            stroke = null;
            fill = null;

            // Try to find colors in palette.
            // We draw from 0 upwards or from a negative value upwards to 0.
            double lower = Math.Min(0, paletteIndex);
            double higher = Math.Max(0, paletteIndex);

            //if (FillMode == AreaFillMode.Solid)
            //{
            //  // Fill legend symbol with single color.
            //  lower = higher;
            //}

            // Define gradient direction.
            Point startPoint;
            Point endPoint;
            if (PaletteIndex == PaletteIndex.Index || PaletteIndex == PaletteIndex.XValue ||
                FillMode == AreaFillMode.GradientHorizontal || FillMode == AreaFillMode.Solid)
            {
                startPoint = new Point(0, 0);
                endPoint = new Point(1, 0);
                if (xAxis != null && xAxis.Scale != null && xAxis.Scale.Reversed)
                    ChartHelper.Swap(ref startPoint, ref endPoint);
            }
            else
            {
                startPoint = new Point(0, 1);
                endPoint = new Point(0, 0);
                if (yAxis != null && yAxis.Scale != null && yAxis.Scale.Reversed)
                    ChartHelper.Swap(ref startPoint, ref endPoint);
            }

            // Get brush for fill and stroke.
            if (FillPalette != null && FillPalette.Count > 0)
            {
                fill = new LinearGradientBrush
                {
                    GradientStops = FillPalette.GetGradient(lower, higher),
                    StartPoint = startPoint,
                    EndPoint = endPoint,
                    ColorInterpolationMode = FillPalette.ColorInterpolationMode
                };
            }

            if (StrokePalette != null && StrokePalette.Count > 0)
            {
                stroke = new LinearGradientBrush
                {
                    GradientStops = StrokePalette.GetGradient(lower, higher),
                    StartPoint = startPoint,
                    EndPoint = endPoint,
                    ColorInterpolationMode = StrokePalette.ColorInterpolationMode
                };
            }
        }
Пример #6
0
        protected virtual void OnGetStrokeAndFillForSegment(int index, out Brush stroke, out Brush fill)
        {
            Axis xAxis = XAxis;
            Axis yAxis = YAxis;

            // Check coloring parameters.
            if (PaletteIndex == PaletteIndex.Index && FillMode == AreaFillMode.GradientVertical
                || PaletteIndex == PaletteIndex.XValue && FillMode == AreaFillMode.GradientVertical)
            {
                throw new NotSupportedException("Vertical gradients are only supported if the palette is indexed by y values.");
            }

            // Find palette index.
            double paletteIndex = 0;
            switch (PaletteIndex)
            {
                case PaletteIndex.Index:
                    paletteIndex = index;
                    break;
                case PaletteIndex.XValue:
                    paletteIndex = Data[index].X;
                    break;
                case PaletteIndex.YValue:
                    paletteIndex = Data[index].Y;
                    break;
                default:
                    throw new NotSupportedException("PaletteIndex type is not supported.");
            }

            // Set default values for stroke and fill brush.
            stroke = null;
            fill = null;

            // Try to find colors in palette.
            if (FillMode == AreaFillMode.Solid)
            {
                // Solid:
                // Get a solid color fill for fill and stroke.
                if (FillPalette != null && FillPalette.Count > 0)
                    fill = new SolidColorBrush(FillPalette.GetColor(paletteIndex));

                if (StrokePalette != null && StrokePalette.Count > 0)
                    stroke = new SolidColorBrush(StrokePalette.GetColor(paletteIndex));
            }
            else
            {
                // Get data values.
                DataPoint data = Data[index];
                DataPoint dataBase = new DataPoint(data.X, 0, null);                          // The base is currently always y = 0.
                DataPoint previousData = (index > 0) ? Data[index - 1] : data;
                DataPoint previousDataBase = new DataPoint(previousData.X, 0, null);          // The base is currently always y = 0.
                DataPoint nextData = (index < Data.Count - 1) ? Data[index + 1] : data;
                DataPoint nextDataBase = new DataPoint(nextData.X, 0, null);                  // The base is currently always y = 0.

                // Gradient:
                double fillStart;
                double fillEnd;
                double strokeStart;
                double strokeEnd;

                // Define palette index values.
                ChartInterpolation interpolation = EffectiveInterpolation;
                if (PaletteIndex == PaletteIndex.Index)
                {
                    // Index-based
                    if (interpolation == ChartInterpolation.CenteredSteps)
                    {
                        fillStart = strokeStart = Math.Max(index - 0.5, 0);
                        fillEnd = strokeEnd = Math.Min(index + 0.5, Data.Count - 1);
                    }
                    else if (interpolation == ChartInterpolation.LeftSteps)
                    {
                        fillStart = strokeStart = Math.Max(index - 1, 0);
                        fillEnd = strokeEnd = index;
                    }
                    else
                    {
                        fillStart = strokeStart = index;
                        fillEnd = strokeEnd = index + 1;
                    }
                }
                else if (PaletteIndex == PaletteIndex.XValue)
                {
                    // x value based
                    if (interpolation == ChartInterpolation.CenteredSteps)
                    {
                        fillStart = strokeStart = (previousData.X + data.X) / 2;
                        fillEnd = strokeEnd = (data.X + nextData.X) / 2;
                    }
                    else if (interpolation == ChartInterpolation.LeftSteps)
                    {
                        fillStart = strokeStart = previousData.X;
                        fillEnd = strokeEnd = data.X;
                    }
                    else
                    {
                        fillStart = strokeStart = data.X;
                        fillEnd = strokeEnd = nextData.X;
                    }
                }
                else
                {
                    // y value based
                    if (FillMode == AreaFillMode.GradientHorizontal)
                    {
                        if (interpolation == ChartInterpolation.CenteredSteps)
                        {
                            fillStart = strokeStart = (previousData.Y + data.Y) / 2;
                            fillEnd = strokeEnd = (data.Y + nextData.Y) / 2;
                        }
                        else if (interpolation == ChartInterpolation.LeftSteps)
                        {
                            fillStart = strokeStart = previousData.Y;
                            fillEnd = strokeEnd = data.Y;
                        }
                        else
                        {
                            fillStart = strokeStart = data.Y;
                            fillEnd = strokeEnd = nextData.Y;
                        }
                    }
                    else
                    {
                        fillStart = Math.Min(0, Math.Min(data.Y, dataBase.Y));
                        fillEnd = Math.Max(0, Math.Max(data.Y, dataBase.Y));
                        if (interpolation == ChartInterpolation.Linear)
                        {
                            fillStart = Math.Min(fillStart, Math.Min(nextData.Y, nextDataBase.Y));
                            fillEnd = Math.Max(fillEnd, Math.Max(nextData.Y, nextDataBase.Y));
                        }

                        // This is the only case where the stroke has a different start and end value than the fill.
                        // (Because the fill starts at y=0, but the line starts at the data point.)
                        strokeStart = data.Y;
                        strokeEnd = nextData.Y;
                        if (strokeStart > strokeEnd)
                            ChartHelper.Swap(ref strokeStart, ref strokeEnd);
                    }
                }

                // Define gradient direction.
                Point startPoint;
                Point endPoint;
                if (PaletteIndex == PaletteIndex.Index || PaletteIndex == PaletteIndex.XValue || FillMode == AreaFillMode.GradientHorizontal)
                {
                    startPoint = new Point(0, 0);
                    endPoint = new Point(1, 0);
                    if (xAxis != null && xAxis.Scale != null && xAxis.Scale.Reversed)
                        ChartHelper.Swap(ref startPoint, ref endPoint);
                }
                else
                {
                    startPoint = new Point(0, 1);
                    endPoint = new Point(0, 0);
                    if (yAxis != null && yAxis.Scale != null && yAxis.Scale.Reversed)
                        ChartHelper.Swap(ref startPoint, ref endPoint);
                }

                // Get brush for fill and stroke.
                if (FillPalette != null && FillPalette.Count > 0)
                {
                    fill = new LinearGradientBrush
                    {
                        GradientStops = FillPalette.GetGradient(fillStart, fillEnd),
                        StartPoint = startPoint,
                        EndPoint = endPoint,
                        ColorInterpolationMode = FillPalette.ColorInterpolationMode
                    };
                }

                if (StrokePalette != null && StrokePalette.Count > 0)
                {
                    stroke = new LinearGradientBrush
                    {
                        GradientStops = StrokePalette.GetGradient(strokeStart, strokeEnd),
                        StartPoint = startPoint,
                        EndPoint = endPoint,
                        ColorInterpolationMode = StrokePalette.ColorInterpolationMode
                    };
                }
            }
        }