从另一个线程更快地刷新TextBlock

时间:2016-02-19 10:33:28

标签: wpf multithreading data-binding

我确实有一个WPF应用程序实时显示数据(从另一个线程计算)。但我的UI组件(此处为TextBlock)更新速度非常慢。 我使用传统数据绑定PropertyChanged通知。 xaml:

<TextBlock
          Foreground="DarkGray"
          Text="{Binding Path=ContactSurface, StringFormat='{}{0:0.00} cm²'}"/>

代码隐藏(不,这不是MVVM,对我感到羞耻):

private double _contactSurface;
    public double ContactSurface
    {
        get { return _contactSurface; }
        set { _contactSurface = value; RaisePropertyChanged("ContactSurface"); }
    }

    public void Compute() // external thread about 10 Hz
    {
        ContactSurface = (double)nbSensorsNotNulls * DataSource.SensorSurface * 0.01;

        Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() => { })); // does not change a thing
        //Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() => { })); // crash : Cannot perform this operation while dispatcher processing is suspended.

        //UpdateLayout(); // crash : The calling thread can not access this object because a different thread owns it
        //InvalidateVisual(); // crash : The calling thread can not access this object because a different thread owns it

    }

我在Compute()结束时尝试了一些我在网络上发现的一些非常均值的结果

1 个答案:

答案 0 :(得分:2)

如果您在另一个线程中执行一些耗时的工作,那么必须将另一个线程的结果与UI线程同步。要同步两个线程(新线程和UI线程),必须使用 Dispatcher

As MSDN says:

  

只有一个线程可以修改UI线程。但背景线程如何相互作用   与用户?后台线程可以要求UI线程执行   代表它运作。它通过注册工作项来实现   UI线程的Dispatcher。 Dispatcher类提供了两个   注册工作项的方法:Invoke和BeginInvoke。都   方法安排委托执行。 Invoke是一个同步   调用 - 也就是说,直到实际的UI线程才会返回   完成执行代理。 BeginInvoke是异步的   马上回来。

例如:

Task.Run(()=> {
   var result = (double)nbSensorsNotNulls * DataSource.SensorSurface * 0.01;
   Thread.Sleep(5000);//imitate time consuming work
   Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render,
            new Action(() => { 
                            ContactSurface=result;}));
});

在上面的例子中,我们创建一个新线程(Task.Run(...))并将新线程的结果与UI线程(Dispatcher.BeginInvoke(...))同步