I am facing a complex bug with the Dundas Charting for Winforms tool used with MS Visual Studio 2008 C#.
The following error occurs when a GUI event is raised on the Chart object while it’s invalidating. When the error happens the dundas chart shows a big X mark. ...
************** Exception Text **************
System.ArgumentOutOfRangeException: Axis Object - The Interval can not be zero
Parameter name: diff
at Dundas.Charting.WinControl.AxisScale.a(Double )
at Dundas.Charting.WinControl.Axis.a(Double , Double , AxisScaleSegment , DateTimeIntervalType& )
at Dundas.Charting.WinControl.Axis.a(ChartGraphics , Boolean , AxisScaleSegment , Boolean )
at Dundas.Charting.WinControl.Axis.b(ChartGraphics , Boolean , Boolean )
at Dundas.Charting.WinControl.Axis.Resize(ChartGraphics chartGraph, ElementPosition chartAreaPosition, RectangleF plotArea, Single axesNumber, Boolean autoPlotPosition)
at Dundas.Charting.WinControl.ChartArea.a(ChartGraphics )
at Dundas.Charting.WinControl.ChartPicture.Resize(ChartGraphics chartGraph, Boolean calcAreaPositionOnly)
at Dundas.Charting.WinControl.ChartPicture.Paint(Graphics graph, Boolean paintTopLevelElementOnly, RenderingType renderingType, XmlTextWriter svgTextWriter, Stream flashStream, String documentTitle, Boolean resizable, Boolean preserveAspectRatio)
at Dundas.Charting.WinControl.ChartPicture.Paint(Graphics graph, Boolean paintTopLevelElementOnly)
at Dundas.Charting.WinControl.Chart.OnPaint(PaintEventArgs e)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
The scenario is as follows:
This is the event that causes the crash:
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
AppDataSeries boundData =
dataGridView1[e.ColumnIndex, e.RowIndex].OwningRow.DataBoundItem as AppDataSeries;
if (boundData.Tag != null)
// Tag is of Type Dundas.Charting.WinControl.Series
{
switch (e.ColumnIndex)
{
case 1:
MUChart.Series[boundData.SeriesName].ChartArea =
boundData.ChartArea.ToString();
// when you change the chart area of a series it
// crashes the chart control
// also when you enable or disable a series using
// series1.Enabled = true,
// it could crash the chart control
MUChart.ChartAreas[boundData.ChartArea].Visible = true;
break;
}
}
}
}
The drawing is done in the following manner
A background thread is capturing
It is raising the event
OnDataAvailable every second
Here’s the handler
void serviceWrapperInstance_DataAvailable(object sender, DataAvailableEventArgs e)
{
if (e.ViewId == currentViewId)
{
if (MUChart.InvokeRequired)
{
MUChart.Invoke((MethodInvoker)AddData);
}
else
{
AddData();
}
}
}
public void AddData()
{
if (MUChart.Series.Count > 0)
{
for (int i = 0; i < currentViewSeries.Count; i++)
{
AddNewPoint(currentViewSeries[i].XValue, MUChart.Series[i],
currentViewSeries[i].YValue * ((currentViewSeries[i].IsInverse) ? -1 : 1),
currentViewSeries[i].ChartColor);
dataSaver[MUChart.Series[i].Name].Add(new DataPoint(currentViewSeries[i].XValue,
(double)currentViewSeries[i].YValue));
}
}
}
public void AddNewPoint(double xValue, Series ptSeries, double yValue,
Color pointColor)
{
try
{
ptSeries.Points.AddXY(xValue, yValue);
if (draggedDroppedSeriesMapper.ContainsKey(ptSeries))
foreach (Series item in draggedDroppedSeriesMapper[ptSeries].DraggedDroppedSeriesVersions)
item.Points.AddXY(xValue, yValue);
MUChart.Invalidate();
// if I remove the previous line the plot doesn’t crash, but doesn’t update !!
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "AddNewPoint()", ex);
}
}
The interesting thing about this bug is that it doesn’t happen on all machines. I noticed that it happens on high specs machines like our 8 core CPU DELL machine, and a new quad core laptop that we got here. This raised the suspect of a threading problem; however, threading seems to be okay since the chart object is accessed from the same main thread.
Please help me with this
UPDATE the assignment using the setter that takes place in the function dataGridView1_CellEndEdit MUChart.Series[boundData.SeriesName].ChartArea = boundData.ChartArea.ToString(); calls chart.invalidate internally, while the invoked function 'AddData' that updates that chart calls it explicitly. I read in the MSDN library that "control.invalidate" doesn't force a synchronous paint unless control.update is called after it. I am almost certain that the conflict is happening upon invalidation even though everything is happening on the same thread since the redrawing is taking place asynchorounsely . I understood what's happening this way but I don't know how to avoid it. control.update is doing me no good.
ChangeTheChartConfigurations(); DrawTheChanges() ---- >>>> this works asynchronously UpdateDataPoints() DrawTheChanges() ---- >>> this works while the first change has still not occured yet. For example, the series might have been moved to a difference chart area and Dundas.Charting.WinControl.AxisScale.a(Double ) (the last function in the stack trace)is being called on already hidden chart area.. that's just a thought
UPDATE
I logged the thread ID from both the event handler and the AddNewPoint function and it was the same as the main thread's
Rather than invalidating the chart after drawing each point, draw all the points and then invalidate the chart once. Try moving MUChart.Invalidate() from AddNewPoint() to after the for loop in AddData().
I think you should not call
MUChart.Series[boundData.SeriesName].ChartArea = boundData.ChartArea.ToString();
directly. You should wrap it to InvokeRequired/Invoke code. And the same for
MUChart.ChartAreas[boundData.ChartArea].Visible = true;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With