문제

I have a treeView element where every node represent a double list.

I'm using a DataVisualization.Charting control to display the values in the list.

For some of the lists I get an exception after RecalculateAxesScale (System.OverflowException: Value was either too large or too small for a Decimal). I ignore this error and therefore the chart displays a big red cross.

When I now click on another node I want to display the chart of this double list (which is valid), but my chart is not redrawn. It always displays the red X.

My code:

private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{

//Refresh chart:
chart1.Series.Clear();
chart1.ResetAutoValues();
chart1.ResetText();

//plot new doublelist
var series = new Series
{
   Name = "name",
   Color = color,
   ChartType = SeriesChartType.Line,
   ChartArea = "chartName"
};

this.chart1.Series.Add(series);
    series.Points.DataBindY(doubleList);
    var chartArea = chart1.ChartAreas["chartName"];
    chartArea.RecalculateAxesScale();
    chartArea.AxisX.Minimum = 1;
    chartArea.AxisX.Maximum = doubleList.Count;
    chartArea.CursorX.AutoScroll = true;
    chartArea.CursorY.AutoScroll = true;

    // Allow user to select area for zooming
    chartArea.CursorX.IsUserEnabled = true;
    chartArea.CursorX.IsUserSelectionEnabled = true;

    // Set automatic zooming`<br>
    chartArea.AxisX.ScaleView.Zoomable = true;
    chartArea.AxisY.ScaleView.Zoomable = true;
    chartArea.AxisX.ScrollBar.IsPositionedInside = true;

    //reset zoom
    chartArea.AxisX.ScaleView.ZoomReset();
    chart1.Invalidate();
}

[EDIT]

Type of dblList:

List<double> doubleList= (from s in myData select s.value).ToList(); 

Full stack of Exceptions:

{System.OverflowException: Value was either too large or too small for a Decimal.
at System.Decimal.FCallMultiply(Decimal& d1, Decimal& d2)
at System.Decimal.op_Multiply(Decimal d1, Decimal d2)
at System.Windows.Forms.DataVisualization.Charting.Axis.RoundedValues(Double inter, Boolean shouldStartFromZero, Boolean autoMax, Boolean autoMin, Double& min, Double& max)
at System.Windows.Forms.DataVisualization.Charting.Axis.EstimateNumberAxis(Double& minimumValue, Double& maximumValue, Boolean shouldStartFromZero, Int32 preferredNumberOfIntervals, Boolean autoMaximum, Boolean autoMinimum)
at System.Windows.Forms.DataVisualization.Charting.Axis.EstimateAxis(Double& minimumValue, Double& maximumValue, Boolean autoMaximum, Boolean autoMinimum)
at System.Windows.Forms.DataVisualization.Charting.Axis.EstimateAxis()
at System.Windows.Forms.DataVisualization.Charting.ChartArea.SetDefaultAxesValues()
at System.Windows.Forms.DataVisualization.Charting.ChartArea.SetData(Boolean initializeAxes, Boolean checkIndexedAligned)

at System.Windows.Forms.DataVisualization.Charting.ChartArea.RecalculateAxesScale()

[EDIT 2]

Example List:

   List<double> dblList = new List<double>();
   dblList.Add(0.0);
   dblList.Add(-7.4876421623346545E-36);
   dblList.Add(1.0);
   dblList.Add(-26697097281536.0);
   dblList.Add(-6.8163553952838136E+28); //problem!!!!!

The last value produces the problem (red cross without exception). So it seems that the min and max values for converting the list are not appropriate. Any ideas on that?

 double min = (double)Decimal.MinValue; //min = -7.9228162514264338E+28
 double max = (double)Decimal.MaxValue; //max =  7.9228162514264338E+28
도움이 되었습니까?

해결책

The error in RecalculateAxesScale (System.OverflowException: Value was either too large or too small for a Decimal) was thrown, because of a Bug in the Library. It uses decimal values inside the implementation of chart functions (especially in axes recalculation/zoom), which causes the problem.

Just checking for every chart point if its value is lower or greater than

double min = (double)Decimal.MinValue;
double max = (double)Decimal.MaxValue;

and replace it by this values didn't solve the problem.

I chose -/+7.92E+27 as bounds instead of the ones above and everything is working fine now.

다른 팁

So the solution proffered thus far is almost, but not quite, correct. If it was open source I could find an remedy the problem directly, but alas I must only surmise as to the actual implementation. The chart library appears to convert to Decimal, and throws an exception when the value range is exceeded while converting from double. The obvious solution of checking for all out-of-range values and setting to Decimal.MinValue and Decimal.MaxValue fails with the same exception. In fact, the actual max and min values allowed by the charting engine was found by myself, through some experimentation, to be approximately an order of magnitude less.

Enough discussion, here is my working source code for a TVQ chart with sometimes bound-exceeding double values. Max and min chart values are pre-calculated for efficiency. Replace all calls to AddXY with SafeChartDouble. Change the AxisX datatype as necessary for your application.

    private static readonly double SCALE_FACTOR = 10;
    private static readonly double MIN_CHART_VALUE
        = Convert.ToDouble(Decimal.MinValue) / SCALE_FACTOR;
    private static readonly double MAX_CHART_VALUE
        = Convert.ToDouble(Decimal.MaxValue) / SCALE_FACTOR;

    private void SafeChartDouble(Series cs, DateTime ts, double dv)
    {
        // microsoft chart component breaks on very large/small values
        double chartv;
        if (dv < MIN_CHART_VALUE)
        {
            chartv = MIN_CHART_VALUE;
        }
        else if (dv > MAX_CHART_VALUE)
        {
            chartv = MAX_CHART_VALUE;
        }
        else
        {
            chartv = dv;
        }
        cs.Points.AddXY(ts, chartv);
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top