我正面临着与MS Visual Studio 2008 C#一起使用的Dundas Charting for Winforms工具的复杂错误。
在Chart对象失效时,如果在GUI对象上引发GUI事件,则会发生以下错误。当错误发生时,dundas图表显示一个很大的X标记。 ......
************** 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)
方案如下:
这是导致崩溃的事件:
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;
}
}
}
}
绘图以下列方式完成
后台线程正在捕获
正在举起活动
OnDataAvailable每秒
这是处理程序
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);
}
}
这个bug的有趣之处在于它不会在所有机器上发生。我注意到它发生在高规格的机器上,比如我们的8核CPU DELL机器,以及我们在这里购买的新四核笔记本电脑。这引起了线程问题的嫌疑人;但是,线程似乎没问题,因为图表对象是从同一主线程访问的。
请帮我解决这个问题
更新 使用函数dataGridView1_CellEndEdit中发生的setter赋值 MUChart.Series [boundData.SeriesName] .ChartArea = boundData.ChartArea.ToString();在内部调用chart.invalidate, 而更新该图表的调用函数“AddData”会显式调用它。我在MSDN库中读到“control.invalidate”不强制同步绘制,除非在它之后调用control.update。我几乎可以肯定,即使一切都发生在同一个线程上,由于重绘正在异步进行,冲突也会在失效时发生。 我理解这种情况正在发生,但我不知道如何避免它。 control.update对我没有好处。
ChangeTheChartConfigurations(); DrawTheChanges()----&gt;&gt;&gt;&gt;这是异步工作 UpdateDataPoints() DrawTheChanges()----&gt;&gt;&gt;这是有效的,而第一次改变还没有发生。例如,系列可能已被移动到差异图表区域,Dundas.Charting.WinControl.AxisScale.a(Double)(堆栈跟踪中的最后一个函数)正在已隐藏的图表区域上调用。 这只是一个想法
更新
我从事件处理程序和AddNewPoint函数中记录了线程ID,它与主线程的
相同答案 0 :(得分:2)
我认为你不应该打电话
MUChart.Series[boundData.SeriesName].ChartArea = boundData.ChartArea.ToString();
直接。您应该将其包装到InvokeRequired / Invoke代码中。
同样如此MUChart.ChartAreas[boundData.ChartArea].Visible = true;
答案 1 :(得分:2)
绘制每个点后,不是使图表无效,而是绘制所有点,然后使图表无效一次。尝试将AddNewPoint()中的MUChart.Invalidate()移动到AddData()中的for循环之后。
答案 2 :(得分:1)
您可能有跨线程操作。
尝试在添加所有点并在主GUI线程中放置MUChart.Invalidate。
当您从另一个线程访问UI控件而不是UI线程时,红色十字通常由.NET框架本身绘制。
当资源不可用或显示控件时发生异常时,也会显示交叉。
答案 3 :(得分:1)
我怀疑你有一个被处置的物体。 (这是你得到的一种奇怪的例外。)一个迹象表明它发生在高端机器上。意思是,机器进行了垃圾收集。
1)当您调用Refresh而不是Invalidate时会发生什么?
2)删除长链对象引用并创建变量。您了解每个{}创建一个本地范围(堆栈)。在图表更新时,这可能会导致对象的范围发生变化。做Series s = MUChart.Series[boundData.SeriesName]; ChartArea a = s.ChartArea;
等等。
3)尝试在AddNewPoint或AddData中锁定或同步对象。您可能正在做的事情也不是控件的线程安全。检查文档。
4)我不会在AddNewPoint中放置try:catch。更好的方法是将它放在for循环之外,但在你的情况下将它放在循环中。
5)你真的不应该使用刷新,更新和无效的调用。这表明您的实现需要减少CPU周期。 (例如,删除try:catch,使用同步锁定解决任何多个“Data Available”事件,删除AddNewPoint方法。)
答案 4 :(得分:0)
请关注以下错误:
间隔不能为零参数 name:diff
我认为图表x轴的两个值具有相同的值,因此会引发异常。
答案 5 :(得分:0)
我遇到了同样的错误,发现原因是我将AxisIntervalMode设置为VaiableCount,即使没有数据也是如此。所以我根据系列是否有数据动态更改AxisIntervalMode。希望这可以帮助别人。