2011-05-10 40 views
2
  • 我工作的一个Windows窗体应用程序(.NET 4.0)。
  • 我的表单包含使用VS2010中包含的Microsoft图表控件的“Fast Line”图表。
  • 该图表充满大约20,000个数据点。
  • 我的应用程序,然后开始从通过DDE(动态数据交换),实时接收服务器市场数据并将其添加到图表。

注:我没有对服务器无法控制,所以我必须处理DDE仅即使它是一种过时的技术。 VS不再支持DDE,所以我使用Ndde库,它的功能就像一个魅力。如何缓存实时数据?

首先,我们连接到服务器,创建一个提醒循环,然后订阅OnAdvise事件接收新数据的通知:

Dim client As DdeClient = New DdeClient("ServerApplication", "Bid") 

Private Sub StartDDE() 
    client.Connect() 
    client.StartAdvise("EURUSD", 1, True, 60000) 
    AddHandler client.Advise, AddressOf OnAdvise 
End Sub 

现在我们可以把这些命令来更新里面的图表事件:

Private Sub OnAdvise(ByVal sender As Object, ByVal args As DdeAdviseEventArgs) 
    Dim myPrice As Double = args.Text 
    Chart1.Series("Bid").Points.AddY(myPrice) 
End Sub 

你的想法。

问题:

也能正常工作了几秒钟,直到图表崩溃引发异常:“集合已修改;枚举操作可能不会执行”

我花了很多时间研究什么可能是这个原因在我的具体情况,和我来,这是因为图表接收数据的速度比它可以处理的结论。它已经加载了大量的数据,需要一定的时间(少于一秒)才能将接收到的数据添加到新的DataPoint中并使其自动失效(刷新)。而服务器通常非常快速地发送数据值(例如中间5ms)。所以我尝试了以下内容:

System.Threading.Thread.Sleep(800) 
Chart1.Series("Bid").Points.AddY(myPrice) 

因此暂停应用程序可以给时间图表添加新点前完成其工作,你猜怎么着?在抛出异常之前,应用程序现在可以运行数分钟。 (改变Sleep()中的值并没有帮助)然而,

我唯一可以在网上找到的帮助是有人提到你应该将传入的数据放入缓存队列中,有一个新的数据值一次从现金中释放(每次图表完成工作时)。

我的问题是你会怎么做呢?

欢迎您提出其他建议!

+3

任何机会,从一个非UI线程更新图表数据采集是吗? – Gabe 2011-05-10 18:40:19

+0

这听起来像是一个线程问题 - 有人试图在枚举时修改集合。 – rsbarro 2011-05-10 18:47:17

+0

OnAdvise是一个事件委托功能吗?尝试调用方法AddY而不是执行。 (或者更好的办法是查看InvokeRequired的值,假设这个值是真的,我认为这是真的,如果没有调用它(同步地将数据传递给另一个线程),你不能安全地调用它。但是,需要做的事情是将结果中的附加点保留下来,并在停止迭代数据点之后添加它们。在迭代过程中,集合不会被改变,而下一个传递将会有更新的数据。 – 2011-05-10 18:48:01

回答

2

这是最有可能发生企图从比UI线程以外的线程修改UI元素的问题。

你现在所编码的DdeClient.Advise事件处理程序正在由库管理的工作线程的执行方式。看,DDE糟透了,因为它吸收它有这些要求,它必须在消息泵的线程上运行。 为了使库与除了Windows窗体以外的其他类型的应用程序兼容,我编码它的方式是它将创建一个带有消息循环的专用线程,并将所有操作编组到默认情况下。

但是,您可以通过在DdeClient构造函数中手动指定ISynchronizeInvoke实例来覆盖此行为。然后该库将使用任何线程为其所有的DDE操作托管ISynchronizeInvoke实例。所有FormControl实例都实现了ISynchronizeInvoke,因此很容易告诉库使用主UI线程。

Dim client As DdeClient = New DdeClient("ServerApplication", "Bid", yourForm) 

如果你告诉库,然后用你的Form实例Advise事件处理程序将承载相同的线程上执行的Form; UI线程。

顺便说一句,我意识到你无法控制服务器,但我至少会开始与软件供应商交谈,以使用更现代(而不是20年)的机制来进行进程间通信。


它也有这使得处理垃圾收集一个真正的痛苦线程相似的不幸需求。

+0

很棒的回答。感谢Brian的洞察力。哦,我不能同意DDE。我们在发言时正在向供应商发送电子邮件。 – Marven 2011-05-10 20:00:17

0

Get real;)DDE速度慢,图形速度慢。不要在同一个线程中执行它们。

试一下:

  • 创建处理DDE第二个线程,队列中的项目。
  • 图表线程然后拉动更新并绘制它们。

现在,来了一点:

  • 只有UI线程被允许修改图表控件。是的,很烂。不,不可谈判。 - 自创建以来的旧UI规则。
  • 线程需要锁定;)