如何使用数据绑定更新C#图表控件

3
我有一个C#图表控件,我像这样绑定数据。
chart.Series[0].Points.DataBindXY(xAxis, yAxis);
where xAxis is List<String> and yAxis is List<Double>

在另一个线程中,xAxis和yAxis会不断更新(多次调用.Add())。
然而,除非我再次调用DataBindXY(),否则图表不会更新。但是这似乎会导致问题,因为偶尔会出现以下错误:
 Error: "Collection was modified; enumeration operation may not execute." 

在某个时刻,这会导致我的程序崩溃。
 Error: "system.reflection.targetinvocationexception' occurred in mscorlib.dll"

-我在更新方面是否有什么遗漏?或者我应该以不同的方式进行更新,如果您需要更多信息,请告诉我。

2个回答

3
您需要在更新方法和DataBindXY方法中添加锁定或同步。因为列表上的操作不是线程安全的,所以您不能同时修改并读取一个列表。我建议阅读此(或其他许多)C#线程同步介绍:http://msdn.microsoft.com/en-us/library/ms173179.aspx
编辑:以下是如何执行此操作的示例:
Object lockOnMe = new Object();

... in your Add loop

(int i = 0; i < dacPoints.Count; i += 1) { 
    TimeSpan span = new TimeSpan(0, 0, i + 1); 
    lock (lockOnMe) { 
        presenter.addPoint(span.ToString(), dacPoints[i]); 
    } 
    System.Threading.Thread.Sleep(200); 
}

... when calling DataBindXY()

lock (lockOnMe) {
    // Note that I copy the lists here.  
    // This is because calling DataBindXY is not necessarily a serial, 
    // blocking operation, and you don't want the UI thread touching 
    // these lists later on after we exit the lock
    chart.Series[0].Points.DataBindXY(xAxis.ToList(), yAxis.ToList());
}

好的,我会这样做。如果我之后想出来了,我会告诉你的 =) - hrh
所以我添加了以下代码:for (int i = 0; i < dacPoints.Count; i += 1) { TimeSpan span = new TimeSpan(0, 0, i + 1); lock (xAxisRecent) { lock (yAxisRecent) { presenter.addPoint(span.ToString(), dacPoints[i]); } } System.Threading.Thread.Sleep(200); }并且在调用 DataBindXY 的地方加上相同的锁,但仍然出现了调用异常 =( - hrh
正如我在我的答案中指出的那样,您需要锁定两个线程-一个添加数据点的线程和一个调用DataBindXY的线程。我的建议是只使用一个锁,而不是两个。我会更新我的答案来尝试反映这一点。 - Chris Shain

2
图表控件一次读取数据源(当您发出DataBindXY调用时),这就是它在修改集合时不更新的原因。
您偶尔出现问题的原因是因为后台线程进行更新时正在更改集合,而图表正在从中读取。
您最好将图表轴作为UI线程上创建的ObservableCollection。然后,您可以响应CollectionChanged事件来指示Chart DataBindXY。
然而,为了正确使用此功能,您的后台线程需要在UI线程上调用add调用以添加到集合中。如果您有对chartcontrol的引用,则可以使用control.BeginInvoke调用。

我有点困惑,我尝试了以下代码:public delegate void InvokeDelegateString(string val); chart.BeginInvoke(new InvokeDelegateString(xAxisOb.Add, "ONE")); - hrh
尝试类似这样的代码:chart.BeginInvoke(new Action(()=>xAxisObj.Add("ONE"))); - Bob Vale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接