我确实有一个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()
结束时尝试了一些我在网络上发现的一些非常均值的结果
答案 0 :(得分:2)
如果您在另一个线程中执行一些耗时的工作,那么必须将另一个线程的结果与UI线程同步。要同步两个线程(新线程和UI线程),必须使用 Dispatcher 。
只有一个线程可以修改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(...)
)同步