使用WPF MVVM项目。
在VieModel中,我想在开始一个漫长的过程之前隐藏一个控件。
命令代码如下:
private RelayCommand _DeleteCommand;
public RelayCommand DeleteCommand
{
get
{
return _DeleteReferenceCommand
?? (_DeleteReferenceCommand = new RelayCommand(
() =>
{
GridViewVisibility = false;
//Long process....
},
() => { return ReferencesGridWithPicsUC.SelectedReference != null; }
));
}
}
GridViewVisibility绑定到我对视图的控件可见性并使用raiseevent。 它工作正常,除了在命令返回后实际更新可见性,因此在looong进程之后。 我显然希望它尽快更新。
我尝试使用调度程序并替换为:
GridViewVisibility = false;
与
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
GridViewVisibility = false));
同样的结果。
我怎样才能让它发挥作用?
答案 0 :(得分:2)
您的命令execute方法会阻止UI线程。你正在那里做一些导致UI更新的事情,但是你没有解锁UI线程让UI实际上按照你的要求做。相反,你会继续阻止UI线程很长一段时间。当您停止阻止UI线程时,UI会再次响应并进行更新。
如果您希望在长流程完成之前进行UI更新,则需要为长流程启动一个线程。在旧的MFC时代,我们习惯于抽取消息循环,但随后他们废除了禁令,现在情况有所不同。而且这种方法无论如何都像s ***一样工作,所以最后我们不得不用C ++编写线程,在我的腋下雪中,除了旧袜子之外什么都不吃。我们喜欢它。
Task.Run()
应该做得很好:
private RelayCommand _DeleteCommand;
public RelayCommand DeleteCommand
{
get
{
return _DeleteReferenceCommand
?? (_DeleteReferenceCommand = new RelayCommand(
() =>
{
GridViewVisibility = false;
Task.Run(() =>
{
// Long process....
});
},
() => { return ReferencesGridWithPicsUC.SelectedReference != null; }
));
}
}
你所得到的Dispatcher.BeginInvoke()
并没有做你所猜到的。这是因为通常,如果非UI线程触及UI,则会出现异常。这是不允许的。当您从UI线程外部调用Dispatcher.Invoke()
或Dispatcher.BeginInvoke()
时,它会在 UI线程中执行触摸UI的代码,因此一切正常。
您并不总是需要显式调用:如果控件通过Binding
更新为引发PropertyChanged
的属性,那么将在幕后为您执行调用。这是一种常见的模式,他们将其构建到框架中。但是,INotifyCollectionChanged
不会为您调用。如果您向ObservableCollection
添加项目,则需要Invoke
。如果您只是用新的替换ObservableCollection
,那应该没问题,但如果它是一个大集合,会导致UI无法响应。它实际上更快,但是用户会感觉到它不同于他在旋转器旋转时看到逐个添加到列表中的项目。人类的思想是一件有趣的事情。