我的VM实现了INotifyPropertyChanged接口。我创建了另一个线程T来填充我绑定到Xaml的列表。填充列表后,我在线程T中调用PropertyChanged,我的UI得到了正确的刷新。
我的问题是在什么情况下我需要使用Dispatcher?为什么我不需要在我的情况下使用Dispatcher?我想当其他线程中的代码想要通过将更改排入UI刷新队列来通知UI线程的更改时使用Dispatcher,例如从另一个线程向ObservableCollection添加项,然后UI线程将从队列中提取数据。
private List<string> _ListData;
public List<String> ListData
{
get
{
if (_ListData == null)
Initialise( () => ListData = ReturnSlow());
return _ListData;
}
set { _ListData = value; }
}
private List<string> ReturnSlow()
{
List<string> Test = new List<string>();
Test.Add("1");
Test.Add("2");
Thread.Sleep(2000);
return Test;
}
public void Initialise(Action initialiser)
{
Task t = new Task(() =>
{
initialiser();
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("ListData"));
});
t.Start();
}
答案 0 :(得分:2)
您的应用有一个主UI线程(通常是ManagedThreadId==1
)。如果要从某个其他线程获取的事件更新UI,则必须使用调度程序。这里有用的测试是Dispatcher.CheckAccess()
方法,如果代码在UI线程上,则返回true,如果在其他线程上则返回false。典型的通话类似于:
using System.Windows.Threading; // For Dispatcher.
if (Application.Current.Dispatcher.CheckAccess()) {
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}
else {
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}));
}
如果您在主窗口中,可以使用:
Dispatcher.BeginInvoke(...
如果你在另一个上下文中,例如视图模型,那么使用:
Application.Current.Dispatcher.BeginInvoke(
调用vs BeginInvoke
如果希望当前线程等到UI线程处理了调度代码,请使用Invoke
;如果希望当前线程继续而不等待UI线程上的操作完成,请使用BeginInvoke
。
MessageBox,Dispatchers和Invoke / BeginInvoke:
Dispatcher.Invoke
将阻止您的线程,直到MessageBox被解雇
Dispatcher.BeginInvoke
将允许您的线程代码继续执行,而UI线程将阻止MessageBox调用,直到它被解除。
CurrentDispatcher vs Current.Dispatcher!
是Dispatcher.CurrentDispatcher
的商品,因为我对此的理解是,它将返回当前线程而不是UI线程的Dispatcher。通常,您对UI线程上的调度程序感兴趣 - Application.Current.Dispatcher
始终返回此内容。
附加说明:
如果您发现必须经常检查调度程序CheckAccess,那么有用的辅助方法是:
public void DispatchIfNecessary(Action action) {
if (!Dispatcher.CheckAccess())
Dispatcher.Invoke(action);
else
action.Invoke();
}
可以称为:
DispatchIfNecessary(() => {
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});