views:

96

answers:

4

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?

+1  A: 

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.

CMerat
A: 

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.

pdr
+1  A: 

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.

Reed Copsey
Going to investigate this solution a little bit more, thanks.
Clint
Rx is a pretty intense framework to learn, but some of the capabilities (like this) are amazing, and dramatically simplify your code...
Reed Copsey
+1  A: 

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.

Hans Passant
+1 I've implemented this solution before... feels like such a hack having a "lastMessageSentAt" private variable just to get around the message pump, but whatever works...
Tanzelax