user290986
user290986

Reputation:

Preventing GUI update event floods in .NET

I'm creating a system that takes readings from a hardware device that sends data via a serial port. Every time a "packet" comes in off the serial port, I update and redraw some GUI components to reflect the updated information. Since serial port events stem from a separate thread, I have to call Invoke(Invalidate) on several components to get them to redraw, and this could potentially cause the GUI to get behind the serial port data since the GUI will queue up a bunch of Invoke() requests if the hardware device starts sending, say, 500 packets a second.

Is there any way to find out if there is already an Invoke(Invalidate) request on a GUI component I can prevent the code from queuing up a bunch of these, or should I take a different approach entirely to updating my GUI components?

Upvotes: 2

Views: 403

Answers (5)

Henk Holterman
Henk Holterman

Reputation: 273464

Test and Measure first. Invalidate() is a very (very) cheap function. As long as you don't force any painting (Update, Refresh) you're not likely to have a performance problem.

Your first worry should (probably, now I'm guessing) be the number of Invokes, taxing the MessagePump. Maybe your Received logic can economize a little.

Back to the original question, there exists a Control.Invalidated property but I would expect that that is not safe to call from another thread. And that would defeat the purpose.

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 942000

Keep in mind that you are updating something that's meant for human eyes. We can't see anything but a blur once those updates happen any faster than 25 times per second. So, buffer the data you get from SerialPort and don't Begin/Invoke() until at last 50 msec have passed since the last time you called it.

Either DateTime.UtcNow or Environment.TickCount lets you time this with (just) enough accuracy. You should have no trouble avoiding stalling the UI thread at this rate.

Upvotes: 1

Reed Copsey
Reed Copsey

Reputation: 564641

The best option for this I've seen is to use the new Rx Framework.

By using the Rx framework, you could turn your Serial Port events into an IObservable<T>. If you do this, IObservable<T> provides a Throttle extension method, which allows you to "throttle back" noisy event streams, making them more managable.

Upvotes: 2

pdr
pdr

Reputation: 6440

I would be inclined to put all the information you need in a threadasafe Queue container and have some kind of message pump (most simply, a Timer) in your GUI which reads all items off that queue.

Upvotes: 0

Christian Merat
Christian Merat

Reputation: 4314

Few options off the top of my head:

1) Using an instance variable as a flag: _updatePending set to True before the invoke, set to false when invoke is calling. Don't call Invoke(Invalidate) if flag is True.

2) Use a polling mechanism instead: update the GUI every X ms from a data source that gets updated on the background threads.

Upvotes: 1

Related Questions