Вопрос

I'm trying to render a line graph using MSChart from C# with a dashed style to the line. I have no problems setting the style but I have a large amount of data. This causes the dashed rendering to go wrong as it seems to re-start the "dash" sequence as it draws every line segment. As such I get a line that looks identical to the solid line. If i zoom right in such that my data point density reduces then the dashed style becomes visible.

This is no good for me as I really need it to keep the dashing at any zoom level. Has anyone any ideas as to how this might be possible? It seems strange that it messes up rendering like this to me ...

Any thoughts?

Это было полезно?

Решение

Well this turned into a tad more of a faff than I was expecting. The problem arises due to the fact that MSChart draws the line between each 2 points as a seperate DrawLine call. If the whole things was drawn with one DrawLines call the problem would not exist.

As such I have come up with a method to handle drawing it.

Firstly in the PrePaint I store all the "BorderWidth"s before setting them to 0. This means that MSChart does not draw my lines.

Finally in the PostPaint I draw the lines using the dash style I want. This gives Perfect rendering.

I'm sure there are some edge cases for which my code won't work but this should give you a good idea of how to do it:

    private List< int > mBorderWidths   = null;
    private void LineChartPrePaint( object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e )
    {
        if ( e.ChartElement.GetType() == typeof( System.Windows.Forms.DataVisualization.Charting.ChartArea ) )
        {
            System.Windows.Forms.DataVisualization.Charting.Chart           c   = (System.Windows.Forms.DataVisualization.Charting.Chart)e.Chart;
            System.Windows.Forms.DataVisualization.Charting.ChartArea       ca  = (System.Windows.Forms.DataVisualization.Charting.ChartArea)e.ChartElement;

            mBorderWidths   = new List<int>();
            foreach( System.Windows.Forms.DataVisualization.Charting.Series s in c.Series )
            {
                mBorderWidths.Add( s.BorderWidth );
                s.BorderWidth   = 0;
                s.ShadowOffset  = 0;
            }

            RectangleF rectF    = ca.Position.ToRectangleF();
            rectF               = e.ChartGraphics.GetAbsoluteRectangle( rectF );

            e.ChartGraphics.Graphics.FillRectangle( new SolidBrush( ca.BackColor ), rectF );
        }
        if ( e.ChartElement.GetType() == typeof( System.Windows.Forms.DataVisualization.Charting.Chart ) )
        {
            RectangleF rectF    = e.Position.ToRectangleF();
            rectF               = e.ChartGraphics.GetAbsoluteRectangle( rectF );

            e.ChartGraphics.Graphics.FillRectangle( new SolidBrush( e.Chart.BackColor ), rectF );
        }
    }

    System.Drawing.Drawing2D.DashStyle ChartToDrawingDashStyle( System.Windows.Forms.DataVisualization.Charting.ChartDashStyle cds )
    {
        switch( cds )
        {
            case System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.NotSet:
            case System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid:
                return System.Drawing.Drawing2D.DashStyle.Solid;
            case System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash:
                return System.Drawing.Drawing2D.DashStyle.Dash;
            case System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.DashDot:
                return System.Drawing.Drawing2D.DashStyle.DashDot;
            case System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.DashDotDot:
                return System.Drawing.Drawing2D.DashStyle.DashDotDot;
            case System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dot:
                return System.Drawing.Drawing2D.DashStyle.Dot;
        }
        return System.Drawing.Drawing2D.DashStyle.Solid;
    }

    private void LineChartPostPaint( object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e )
    {
        if ( e.ChartElement.GetType() == typeof( System.Windows.Forms.DataVisualization.Charting.ChartArea ) )
        {
            System.Windows.Forms.DataVisualization.Charting.Chart       c   = (System.Windows.Forms.DataVisualization.Charting.Chart)e.Chart;
            System.Windows.Forms.DataVisualization.Charting.ChartArea   ca  = (System.Windows.Forms.DataVisualization.Charting.ChartArea)e.ChartElement;

            RectangleF clipRect = e.ChartGraphics.GetAbsoluteRectangle( e.Position.ToRectangleF() );
            RectangleF oldClip  = e.ChartGraphics.Graphics.ClipBounds;
            e.ChartGraphics.Graphics.SetClip( clipRect );

            int seriesIdx   = 0;
            foreach( System.Windows.Forms.DataVisualization.Charting.Series s in c.Series )
            {
                PointF  ptFLast         = new PointF( 0.0f, 0.0f );
                List< PointF > points   = new List<PointF>();
                foreach( System.Windows.Forms.DataVisualization.Charting.DataPoint dp in s.Points )
                {
                    double dx   = (double)dp.XValue;
                    double dy   = (double)dp.YValues[0];

                    // Log the value if its axis is logarithmic.
                    if ( ca.AxisX.IsLogarithmic )
                    {
                        dx  = Math.Log10( dx );
                    }
                    if ( ca.AxisY.IsLogarithmic )
                    {
                        dy  = Math.Log10( dy );
                    }

                    dx  = e.ChartGraphics.GetPositionFromAxis( ca.Name, System.Windows.Forms.DataVisualization.Charting.AxisName.X, dx );
                    dy  = e.ChartGraphics.GetPositionFromAxis( ca.Name, System.Windows.Forms.DataVisualization.Charting.AxisName.Y, dy );

                    PointF  ptFThis         = e.ChartGraphics.GetAbsolutePoint( new PointF( (float)dx, (float)dy ) );
                    points.Add( ptFThis );
                }


                if ( points.Count > 0 )
                {
                    Pen pen = new Pen( Color.FromArgb( 255, s.Color ) );
                    pen.Width       = mBorderWidths[seriesIdx];
                    pen.DashStyle   = ChartToDrawingDashStyle( s.BorderDashStyle );
                    //pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
                    //pen.DashPattern   = new float[]{ 4.0f, 4.0f, 1.0f, 3.0f, 2.0f, 3.0f };
                    pen.DashCap     = System.Drawing.Drawing2D.DashCap.Round;

                    e.ChartGraphics.Graphics.SmoothingMode  = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    e.ChartGraphics.Graphics.DrawLines( pen, points.ToArray() );

                }
                s.BorderWidth   = mBorderWidths[seriesIdx];
            }

            e.ChartGraphics.Graphics.SetClip( oldClip );
        }
    }

I truly hope that saves someone some pain!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top