简体   繁体   English

从后台线程更新UI

[英]Updating the UI from a background thread

I have a background task that sits in a loop reading data from an external hardware device. 我有一个后台任务,该任务位于循环中,从外部硬件设备读取数据。 The device exposes a "counter" that increments every 100ms - when this value changes I fetch the next data value from the device and raise an event. 该设备公开了一个“计数器”,该计数器每100ms递增-当此值更改时,我从该设备获取下一个数据值并引发一个事件。 Psuedo-code:- 伪代码:-

public event HasDataEventArgs DataReceived;

while (some condition)
{
    // Wait for device counter to increment
    while (DeviceCounterValue == _lastDeviceCounterValue)
    {
       Thread.Sleep(3);
    }
    _lastDeviceCounterValue = DeviceCounterValue;

    // Read data value from device
    var data = GetDataFromDevice();

    // Raise my event
    DataReceived(this, new HasDataEventArgs(data)); 
}

I also have a UI view that subscribes to this event. 我也有一个订阅此事件的UI视图。 The event handler plots the data value on a chart and sets a number of bound properties. 事件处理程序在图表上绘制数据值并设置许多绑定属性。

Most of the time this all works fine, but if I (say) drag a window around or open a modal dialog, it can occasionally result in data being missed. 在大多数情况下,这一切都可以正常工作,但是如果我(说)在窗口周围拖动或打开模式对话框,它有时会导致数据丢失。 What seems to happen is that the external device counter carries on incrementing, but the 'while' loop has effectively stalled briefly, so misses those changes. 似乎发生的事情是外部设备计数器进行了递增,但是“ while”循环实际上已经短暂停止,因此错过了这些更改。 Very occasionally I'll see the same effect even when I'm not messing around with anything in the UI. 偶然我会看到,即使我不是瞎搞与在UI什么相同的效果。

The event handler in the view isn't doing much, but this is a complex desktop application with other background threads updating other bound controls. 视图中的事件处理程序没有做很多事情,但这是一个复杂的桌面应用程序,具有其他后台线程更新其他绑定控件。 Perhaps this particular process is just tipping things over the edge performance-wise, especially once I start dragging windows around? 也许这个特定的过程只是在性能方面给小费,特别是一旦我开始拖动窗口时?

I was wondering if I could wrap the event handler code in a Task.Run() , which (I assume) would result in it returning control to the while loop immediately, rather than have to wait for the event handler to do its thing. 我想知道是否可以将事件处理程序代码包装在Task.Run()中(我认为)会导致它立即将控制权返回到while循环,而不是必须等待事件处理程序执行其操作。 It sounds hacky though - am I asking for trouble with something like this, especially given the frequency that the event handler will be called (every 100ms)? 但是,这听起来有点骇人听闻-我是否在请求类似问题的麻烦,特别是考虑到事件处理程序的调用频率(每100毫秒)?

You left out some details, mainly what the eventhandler does to get on the GUI thread. 您省略了一些细节,主要是事件处理程序为获得GUI线程所做的工作。 Invoke or BeginInvoke etc. 调用或BeginInvoke等

But there is another option, if safeguarding your data matters most: push the new data into a ConcurrentQueue. 但是,如果保护数据最重要,还有另一种选择:将新数据推送到ConcurrentQueue中。 Raising a Received event is then OK but optional, you probably won't need it. 这样,引发Received事件就可以了,但是是可选的,您可能不需要它。

The Main thread can empty the queue in its own time. 主线程可以在自己的时间内清空队列。 For example with a Timer. 例如使用计时器。

Your screen updates will still stutter but you shouldn't lose data anymore. 屏幕更新仍然会停顿,但您不应再丢失数据。

You have to split (thread-wise) two things: the background work and the plotting work. 您必须拆分(线程方式)两件事:后台工作和绘图工作。 This is, in general, the way how to do such things, but to be concrete - if your plotting requires time, then there are chances that your working thread is not able to handle the incoming data on time and you can get some data lost/omitted (that's what you're actually observing). 通常,这是如何执行此类操作的方式,但要具体地说-如果绘图需要时间,则工作线程可能无法及时处理传入的数据,并且可能会丢失一些数据/ omitted(这就是您实际上正在观察的)。

Here's one way how to do it (the method must be a member of a UI class - Window, user control, etc.): 这是一种实现方法(方法必须是UI类的成员-Window,用户控件等):

void OnDataReceived(object sender, DataEventArgs e)
{
    // here we're in the context of the working thread

    // this call will return immediately giving control back to the working thread
    Dispatcher.BeginInvoke(
        DispatcherPriority.Normal,
        (Action)delegate
        {
            // here we are in the context of the UI thread
        });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM