How to detect unresponsive user interface updates?

Suppose I have a WPF application where I have the following architecture:

[Worker Thread] β†’ [Queue 1] β†’ [Queue Manager Thread] β†’ [Queue 2] β†’ [UI Thread]

An employee listens for data from a service and receives this data at undefined points in time (maybe several times per second or several times in several seconds), and then queues it on queue 1, and then in the queue manager, depending on Moreover, the health of the UI thread may decide to increase / decrease the speed at which data items are queued to Queue 2, which the UI thread uses to update the user interface, perhaps discarding several elements in order not to suppress the user interface flow in the event, he receives too many messages (for example, he may decide that he will check the time stamp of each data message and only put it in queue 2, if the difference between the messages is not less than 5 seconds older than the last data item that the user interface updated itself with)

A timer will be set in the user interface thread, which starts a specified interval for updating the user interface with new data from queue 2. What I would like to do is to determine how quickly the user interface updates itself in order to measure its responsiveness to throttling, for example, increasing / decreasing the timer interval regarding how often the user interface is updated

Suppose there were a lot of controls in my user interface (grids, charts, etc.) that are associated with various filtered / grouped subsets of data in line 2 in my user interface shell, and the user interface begins to stop responding and block updates when updating these controls, can I detect this from the code to find out how / when to increase / decrease the interval for user interface updates? Basically, how can I determine how long it will take to reinstall the entire user interface for all data-bound controls?

By the way, is this a good design or can it be improved? Are there any other strategies that I could consider?

+4
source share
2 answers

I would just reset QueueManager and Queue2.

All you need is a WPF time manager (not Timers.Timer), which checks the input every few ms. You can statically configure this timeout.
And then make Queue1 a blocking queue to throttle everything upstream.

Edit

The dispatcher timer can be started with a specific priority . Choose low, like Background or ContextIdle, and you'll never overload the GUI.
Then just make sure the timer doesn't bite off anymore than it can chew. Only 1 (or several) items at a time. Configure this part so that the graphical interface handles as much as possible, but no more. Runtime tuning is free because you are tied to a dispatcher.

And (only if necessary) you can use Queue1 = new BlockingCollection<MyItemType>(MaxItems) so that this queue does not overflow.

+2
source

There are 2 threads ... the main user interface thread .... and the rendering thread .... you may need to look at both to determine the responsiveness of your application ... and decide how to throttle.

Measure FrameRate

You can watch ETW events or handle CompositionTarget.Rendering and count the frames yourself .... it keeps track of the rendering stream ... if it drops frames, then it can tell you that your system is overloaded ... and you can activate the background accordingly mode.

Use a timer to work with a schedule

You can use DispatcherTimer, as @HenkHolterman mentioned, to control the loading of the UI thread, making it work with a priority lower than Normal, for example. Background .... when the timer event is handled / handled in the user interface thread ... you can then release / inform your background worker about the next work item.

But be careful ... if your time interval is too small ... and your system is overloaded ... then you can get a collection of timer messages ... and therefore, when the event handler is called ... you can do too much work ( if you have not saved the record of the last call).

Run delegate in user interface thread

Alternatively, you can simply get a delegate to run in the user interface thread with a specific priority (for example, usually Background).

If you use Dispatcher.BeginInvoke ..., then the job will be queued and will be executed when all jobs with a higher priority are completed. (Asynchronous).

If you use Dispatcher.Invoke ... then your thread will block until all the higher-priority work in the dispatcher calling you is completed, then your delegate will do it.

(your background worker would do this when he has finished his unit of work, and the delegate will then inform your background worker of the next unit of work).

This may be better than DispatchTimer, as you can remove some delay ... i.e. using a timer will have a delay depending on the timer interval.

Then, depending on what you find, you can configure the next block of work.

Monitoring various system performance counters

If you really want to get complex information, you can control various performance counters inside your application, for example. use memory, GC collections, etc ... and dynamically throttle the amount of work you do.

Some Background Dispatcher

+3
source

All Articles