private void _drawPerspectiveBars(int mod, int rem)
        {
            bool   animate = (this.AnimationDuration > 0);
            double xOffset = XOffsetPerspective, yOffset = YOffsetPerspective;

            double marginLeft = MarginLeft, marginTop = MarginTop;
            double marginRight = MarginRight, marginBottom = MarginBottom;

            double           gridWidth  = (ChartCanvas.Width - marginLeft - marginRight - xOffset);
            double           gridHeight = (ChartCanvas.Height - marginTop - marginBottom - yOffset);
            LookAndFeel      lf         = CurrentLookAndFeel;
            string           pathXAML   = lf.GetBarPathXAML();
            Path             pathElem;
            List <UIElement> dataElems        = null;
            MatrixTransform  defaultTransform = null;

            if (animate)
            {
                dataElems = DataElements;
            }

            int  barItemPadding = _BARITEM_PADDING;
            bool isStacked      = (Type == ChartType.HBAR_STACKED);

            ChartModel model = Model;

            string[] groupLabels = model.GroupLabels;
            int      groupCount  = groupLabels.Length;

            string[] seriesLabels = model.SeriesLabels;
            int      seriesCount  = seriesLabels.Length;

            Color[] seriesColors = model.SeriesColors;
            double[,] yValues = model.YValues;

            double minValue = model.MinYValue, maxValue = model.MaxYValue;

            // For combo graphs we display every once in mod
            int    seriesBars = (mod > 1) ? (int)Math.Ceiling(1 / (double)mod) : seriesCount;
            int    yValueCount = yValues.GetUpperBound(0) + 1;
            double barHeight, stackBase = minValue;

            if (isStacked)
            {
                barHeight = gridHeight / Math.Max(yValueCount, groupCount) - 2 * barItemPadding;
            }
            else
            {
                barHeight = (gridHeight / Math.Max(yValueCount, groupCount)
                             - 2 * barItemPadding - (seriesCount) * barItemPadding) / seriesBars;
            }

            double dx = marginLeft, dy = gridHeight + marginTop + yOffset, barWidth;
            string gradientXAML = lf.GetElementGradientXAML();

            for (int i = 0; i < yValueCount; ++i)
            {
                dy -= barItemPadding;
                dx  = marginLeft;
                for (var j = 0; j < seriesCount; ++j)
                {
                    // for combo charts we draw a bar every once in a mod.
                    if ((mod > 1) && j % mod != rem)
                    {
                        continue;
                    }

                    // If we use non zero min and it is a stacked graph, we need to remove the min for only
                    // the first series.
                    if (isStacked)
                    {
                        stackBase = (j == 0 ? minValue : 0);
                    }

                    barWidth = gridWidth * (yValues[i, j] - stackBase) / (maxValue - minValue);


                    StringBuilder sb = new StringBuilder();
                    sb.Append("M").Append(dx).Append(",").Append(dy);
                    sb.Append(" h").Append(barWidth);
                    sb.Append(" v").Append(-barHeight);
                    sb.Append(" h").Append(-barWidth);
                    sb.Append(" v").Append(barHeight);

                    sb.Append(" M").Append(dx).Append(",").Append(dy - barHeight);
                    sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset);
                    sb.Append(" h").Append(barWidth);
                    sb.Append(" l").Append(-xOffset).Append(",").Append(yOffset);
                    sb.Append(" z");
                    sb.Append(" M").Append(dx + barWidth).Append(",").Append(dy);
                    sb.Append(" v").Append(-barHeight);
                    sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset);
                    sb.Append(" v").Append(barHeight);
                    sb.Append(" z");

                    pathElem = CreatePathFromXAMLAndData(lf.GetBarPathXAML(), sb);

                    if (animate)
                    {
                        dataElems.Add(pathElem);
                        defaultTransform = new MatrixTransform();
                        Matrix m = new Matrix();
                        m.M11 = 0.0;
                        defaultTransform.Matrix = m;
                        pathElem.SetValue(UIElement.RenderTransformProperty, defaultTransform);
                    }

                    pathElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[j]));

                    if (gradientXAML != null)
                    {
                        SetGradientOnElement(pathElem, gradientXAML, seriesColors[j], 0xe5);
                    }
                    else
                    {
                        SetFillOnElement(pathElem, seriesColors[j]);
                    }

                    SetExpandosOnElement(pathElem, i, j, new Point(dx + barWidth + (xOffset) / 2.0, dy - (barHeight + yOffset) / 2.0));

                    if (DisplayToolTip)
                    {
                        pathElem.MouseEnter += new MouseEventHandler(ShowToolTip);
                        pathElem.MouseLeave += new MouseEventHandler(HideToolTip);
                    }

                    pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked);

                    ChartCanvas.Children.Add(pathElem);
                    if (isStacked)
                    {
                        dx += barWidth;
                    }
                    else
                    {
                        dy -= barHeight;
                        dy -= barItemPadding;
                    }
                }
                if (isStacked)
                {
                    dy -= barHeight;
                }
                dy -= barItemPadding;
            }
        }
        private void _drawBars(int mod, int rem)
        {
            bool animate = (this.AnimationDuration > 0);

            double marginLeft = MarginLeft, marginTop = MarginTop;
            double marginRight = MarginRight, marginBottom = MarginBottom;

            double gridWidth  = (ChartCanvas.Width - marginLeft - marginRight);
            double gridHeight = (ChartCanvas.Height - marginTop - marginBottom);

            LookAndFeel      lf       = CurrentLookAndFeel;
            string           rectXAML = lf.GetBarPathXAML();
            Path             rectElem;
            List <UIElement> dataElems        = null;
            MatrixTransform  defaultTransform = null;

            if (animate)
            {
                dataElems = DataElements;
            }

            int  barItemPadding = _BARITEM_PADDING;
            bool isStacked      = (Type == ChartType.HBAR_STACKED);

            ChartModel model = Model;

            string[] groupLabels = model.GroupLabels;
            int      groupCount  = groupLabels.Length;

            string[] seriesLabels = model.SeriesLabels;
            int      seriesCount  = seriesLabels.Length;

            Color[] seriesColors = model.SeriesColors;
            double[,] yValues = model.YValues;

            double minValue = model.MinYValue, maxValue = model.MaxYValue;

            // For combo graphs we display every once in mod
            double barDivider  = isStacked ? 1 : ((mod > 1) ? Math.Ceiling(seriesCount / mod) : seriesCount);
            double stackBase   = minValue;
            int    yValueCount = yValues.GetUpperBound(0) + 1;

            double barHeight = (gridHeight / Math.Max(yValueCount, groupCount) - 2 * barItemPadding) / barDivider;
            double dx = marginLeft, dy = gridHeight + marginTop, barWidth;
            string gradientXAML = lf.GetElementGradientXAML();

            for (int i = 0; i < yValueCount; ++i)
            {
                dy -= barItemPadding;
                dx  = marginLeft;
                for (int j = 0; j < seriesCount; ++j)
                {
                    // for combo charts we draw a bar every once in a mod.
                    if ((mod > 1) && (j % mod) != rem)
                    {
                        continue;
                    }

                    // If we use non zero min and it is a stacked graph, we need to remove the min for only
                    // the first series.
                    if (isStacked)
                    {
                        stackBase = (j == 0 ? minValue : 0);
                    }

                    rectElem = XamlReader.Load(rectXAML) as Path;
                    if (animate)
                    {
                        dataElems.Add(rectElem);

                        // FIXTHIS: This is inefficient. However Silverlight currently does not allow sharing transform attribute
                        defaultTransform = new MatrixTransform();
                        Matrix m = new Matrix();
                        m.M11 = 0.0;
                        defaultTransform.Matrix = m;
                        rectElem.SetValue(UIElement.RenderTransformProperty, defaultTransform);
                    }

                    barWidth = gridWidth * (yValues[i, j] - stackBase) / (maxValue - minValue);
                    RectangleGeometry rectGeometry = new RectangleGeometry();
                    rectGeometry.RadiusX = rectGeometry.RadiusY = 2;
                    rectGeometry.Rect    = new Rect(dx, dy - barHeight, barWidth, barHeight);
                    rectElem.SetValue(Path.DataProperty, rectGeometry);

                    if (gradientXAML != null)
                    {
                        SetGradientOnElement(rectElem, gradientXAML, seriesColors[j], 0xe5);
                    }
                    else
                    {
                        SetFillOnElement(rectElem, seriesColors[j]);
                    }

                    rectElem.SetValue(Rectangle.StrokeProperty, new SolidColorBrush(seriesColors[j]));

                    if (isStacked)
                    {
                        dx += barWidth;
                    }

                    SetExpandosOnElement(rectElem, i, j, new Point(dx + barWidth, dy - barHeight / 2.0));

                    if (DisplayToolTip)
                    {
                        rectElem.MouseEnter += new MouseEventHandler(ShowToolTip);
                        rectElem.MouseLeave += new MouseEventHandler(HideToolTip);
                    }

                    rectElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked);

                    ChartCanvas.Children.Add(rectElem);
                    if (!isStacked)
                    {
                        dy -= barHeight;
                    }
                }
                if (isStacked)
                {
                    dy -= barHeight;
                }
                dy -= barItemPadding;
            }
        }
        public override void DrawChartData()
        {
            bool animate = (this.AnimationDuration > 0);

            double marginLeft = MarginLeft, marginTop = MarginTop;
            double marginRight = MarginRight, marginBottom = MarginBottom;

            double gridWidth  = (ChartCanvas.Width - marginLeft - marginRight);
            double gridHeight = (ChartCanvas.Height - marginTop - marginBottom);

            LookAndFeel      lf       = CurrentLookAndFeel;
            string           rectXAML = lf.GetBarPathXAML();
            Path             rectElem;
            List <UIElement> dataElems        = null;
            MatrixTransform  defaultTransform = null;

            if (animate)
            {
                dataElems = DataElements;
            }

            if (!(Model is CandleStickChartModel))
            {
                throw new Exception("model is not a CandleStickChartModel");
            }

            CandleStickChartModel model = Model as CandleStickChartModel;

            string[] groupLabels = model.GroupLabels;
            int      groupCount  = groupLabels.Length;

            string[] seriesLabels = model.SeriesLabels;
            int      seriesCount  = seriesLabels.Length;

            Color[]      seriesColors       = model.SeriesColors;
            double[][][] candleStickYValues = model.CandleStickYValues;


            double minValue = model.MinYValue, maxValue = model.MaxYValue;
            int    yValueCount = candleStickYValues.Length;
            double barWidth    = ((gridWidth - _PADDING_LEFT) / Math.Max(yValueCount, groupCount));

            double dx = marginLeft + _PADDING_LEFT, dy, barStart, barEnd, stackBase = minValue;
            string gradientXAML = lf.GetElementGradientXAML();

            for (int i = 0; i < yValueCount; ++i)
            {
                dy = gridHeight + marginTop;

                // skip over missing values
                if (candleStickYValues[i] != null)
                {
                    for (int j = 0; j < seriesCount; ++j)
                    {
                        rectElem = XamlReader.Load(rectXAML) as Path;
                        double openValue  = candleStickYValues[i][j][0];
                        double closeValue = candleStickYValues[i][j][3];
                        double highValue  = candleStickYValues[i][j][1];
                        double lowValue   = candleStickYValues[i][j][2];

                        // use the stock open value
                        barStart = (gridHeight + marginTop) - (gridHeight * (openValue - stackBase) / (maxValue - minValue));
                        // use the stock close value
                        barEnd = (gridHeight + marginTop) - (gridHeight * (closeValue - stackBase) / (maxValue - minValue));

                        bool doFill = openValue > closeValue;

                        RectangleGeometry rectGeometry = new RectangleGeometry();
                        rectGeometry.Rect = new Rect(dx, Math.Min(barStart, barEnd), _CANDLE_WIDTH, Math.Abs(barStart - barEnd));
                        rectElem.SetValue(Path.DataProperty, rectGeometry);

                        if (doFill)
                        {
                            if (gradientXAML != null)
                            {
                                SetGradientOnElement(rectElem, gradientXAML, seriesColors[j], 0xe5);
                            }
                            else
                            {
                                SetFillOnElement(rectElem, seriesColors[j]);
                            }
                        }

                        SolidColorBrush scb = new SolidColorBrush(seriesColors[j]);
                        rectElem.SetValue(Rectangle.StrokeProperty, scb);

                        SetExpandosOnElement(rectElem, i, j,
                                             new Point(dx + _CANDLE_WIDTH / 2.0, Math.Min(barStart, barEnd)));

                        if (DisplayToolTip)
                        {
                            rectElem.MouseEnter += new MouseEventHandler(ShowToolTip);
                            rectElem.MouseLeave += new MouseEventHandler(HideToolTip);
                        }

                        rectElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked);
                        ChartCanvas.Children.Add(rectElem);

                        // Draw the sticks for the candle
                        Line lineTop = new Line(), lineBottom = new Line();
                        if (animate)
                        {
                            dataElems.Add(lineTop);
                            dataElems.Add(lineBottom);
                            dataElems.Add(rectElem);
                            defaultTransform = new MatrixTransform();
                            Matrix m = new Matrix();
                            m.M22 = 0.0;
                            defaultTransform.Matrix = m;

                            lineTop.SetValue(UIElement.RenderTransformProperty, defaultTransform);
                            lineBottom.SetValue(UIElement.RenderTransformProperty, defaultTransform);
                            rectElem.SetValue(UIElement.RenderTransformProperty, defaultTransform);
                        }

                        lineTop.SetValue(Line.StrokeProperty, scb);
                        lineBottom.SetValue(Line.StrokeProperty, scb);

                        lineTop.X1    = lineTop.X2 = lineBottom.X1 = lineBottom.X2 = dx + _CANDLE_WIDTH / 2.0;
                        lineTop.Y1    = doFill ? barStart : barEnd;
                        lineTop.Y2    = (gridHeight + marginTop) - (gridHeight * (highValue - stackBase) / (maxValue - minValue));
                        lineBottom.Y1 = doFill ? barEnd : barStart;
                        lineBottom.Y2 = (gridHeight + marginTop) - (gridHeight * (lowValue - stackBase) / (maxValue - minValue));

                        ChartCanvas.Children.Add(lineTop);
                        ChartCanvas.Children.Add(lineBottom);
                    }
                }
                dx += barWidth;
            }
        }