views:

154

answers:

2

Hi All

I am building a real-time multi-threaded application in WPF, but i am having difficulties in updating the UI.

I have a background worker thread that contains logic which determines what trades to send into the market. When a valid trade is sent to the market, i receive status updates on these trades via events in my main application window. I have other events where i receive real-time price updates.

Through these events, i upate the UI. Now it appears that i receive events so rapidly through out the application, that the UI can't keep up with the speed at which events are received - causing the UI to update slowly or not at all. Essentially the UI freezes. After all events have fired, the UI slowly becomes responsive again. Once it is fully responsive, the UI shows the data that i am expecting.

My question is, how do i get the UI to update in real-time as fast as i receive events? I have been struggling with this for a while now, so any help would be appreciated.

Thanks in advance!

+4  A: 

You probably need to coalesce received events such that not every tick results in a GUI update. Batch them up if your GUI is already updating, and have the GUI process the next batch only when it's ready. If the feed is high-volume (frequently the case with active trade data updates) you will not be able to create a GUI that reflects every individual tick as its own self-contained refresh trigger.

Steve Townsend
+1 one can generally only do a limited amount of separate calls to the UI thread per unit of time before it stops being responsive - doing bulk updates of elements like UI lists at a set interval could also help immensely ^^
Oskar Duveborn
+3  A: 

Instead of having the worker thread push the updates to the UI thread via events consider having the UI thread pull (or poll) them periodically. The push method is fine in a lot of situations but has two major disadvantages that are working against you.

  • There is an expensive marshaling operation somewhere that is transferring execution of a method to perform the UI updates safely (at least there should be).
  • The worker thread gets to dictate how often the UI should update and by implication how much work it should perform. It can easily overwhelm the message pump.

I propose using a shared queue in which the worker thread will enqueue a data structure containing the update and the UI thread will dequeue and process it. You can have the UI thread poll the queue at a strategically chosen interval so that it never gets bogged down. The queue will act as the buffer instead of the UI message pump. It will shrink and grow as the amount of updates ebb and flow. Here is a simple diagram of what I am talking about.

[Worker-Thread] -> [Queue] -> [UI-Thread]

I would start with the simple queue approach first, but you could take this to the next logical step of creating a pipeline in which there are 3 threads participating in the flow of updates. The worker thread enqueues updates and the UI thread dequeues them like before. But, a new thread could be added to the mix that manages the number of updates waiting in the queue and keeps it at a manageable size. It will do this by forwarding on all updates if the queue remains small, but will switch into safe mode and start discarding the updates you can live without or combining many into one if a reasonable merge operation can be defined. Here is a simple diagram of how this pattern might work.

[Worker-Thread] -> [Queue-1] -> [Pipeline-Thread] -> [Queue-2] -> [UI-Thread]

Again, start with the simple one queue approach. If you need more control then move to the pipeline pattern. I have used both successfully.

Brian Gideon
Fantastic, thanks Brian. Thats the answer i was looking for. So in a nutshell, instead of allowing the raised events to update the UI, queue them, have a timer which periodically pops these updates off the queue and update the UI. That way the UI is updated within your control, and the timer interval maybe adjusted according to my needs.
c0D3l0g1
Exactly! Let the UI dictate when it is ready to update instead of passing off the responsibility to the worker thread.
Brian Gideon