文章目录
写在前面
- 一点共识:不能从其他线程修改UI界面的属性,比如不能通过其他线程修改Button的Content等等;
- WPF中存在的一种可能:通过数据绑定,可以很大程度上避免直接修改UI界面的元素属性,但仍存在其他线程需要访问修改被绑定的数据集合的问题的可能,本文即对这一问题做解答。
问题描述
public override void SomeLogicMethod()
{
if (ElementViewDataContext != null)
{
var dt = (DataDeliverViewModel)ElementViewDataContext;
dt.brefreshed = false;
MainWindowViewModel.GetInstance().gMainWindow.Dispatcher.BeginInvoke((Action)(() =>
{
dt.init();//涉及到对UI界面元素集合的修改
}));
Log.Logger.Debug("等待数据刷新完成...");
while (!dt.brefreshed)
{
Thread.Sleep(50);
}
Log.Logger.Debug("数据刷新完成!");
dt.brefreshed = false;
}
var b = GetSentValues();
SendValues(b);
IsExecuteDone = true;
}
这里由于涉及到UI界面的修改,所以考虑使用Dispatcher.BeginInvoke
,我们简单回顾一下Dispatcher.BeginInvoke
和Dispatcher.Invoke
。
归纳
BeginInvoke &Invoke
众所周知,BeginInvoke
为异步操作(asyn),Invoke
为同步操作。不知道的是,竟然存在两种不同的BeginInvoke
和Invoke
组合!!来看这篇文章:why there is no EndInvoke in Cross thread UI component call ?
Control.BeginInvoke
和 Dispatcher.BeginInvoke
是不同的。
Control.BeginInvoke
MSDN描述:
Executes a delegate asynchronously on the thread that the control’s underlying handle was created on.
在创建该控件的线程上执行异步委托。这样就解决了跨线程更新的问题。既然异步,那么必然有异步等待的问题,
我们可以通过调用EndInvoke
来确保跨线程执行完毕,如果必要的话。(大多数情况下是没必要的,让UI界面更新的命令下发就可以了,什么时候更新我们并不关心,但是若是涉及到一些数据操作,而我们又需要这部分数据,那么就加等待。以前我的做法是异步+while指定条件手动实现异步等待,现在可以使用EndInvoke
,效率会比自己的阻塞等待