以下示例使用Prism 6.1中的DelegateCommand,但我在5.0中产生了同样的问题。
使用以下视图模型(视图省略,只包含2个按钮):
public class MainWindowViewModel
{
public DelegateCommand TestCommand { get; set; }
public DelegateCommand ActionCommand { get; set; }
public MainWindowViewModel()
{
TestCommand = new DelegateCommand(()=> TestCommand.RaiseCanExecuteChanged());
ActionCommand = new DelegateCommand(() =>
{
Task.Run(() =>
{
Thread.Sleep(1000);
TestCommand.RaiseCanExecuteChanged();
});
});
}
}
如果首先调用ActiveCommand,则会发生此异常:
WindowsBase.dll中出现'System.InvalidOperationException'类型的异常,但未在用户代码中处理
附加信息:调用线程无法访问此对象,因为另一个线程拥有它。
就我所知,这是标准的“如果你不在UI线程上,你就不允许与Wpf控件交谈”例外。这似乎与方法摘要不一致:
在UI线程上引发Prism.Commands.DelegateCommandBase.CanExecuteChanged,这样每个命令调用者都可以重新查询以检查该命令是否可以执行。
此外,我在过去从非UI线程调用此方法时没有问题。
Weirder仍然,如果首先引发TestCommand,那么ActionCommand开始正常工作。我已经检查过,在任何情况下,Task.Run块中的代码都在非UI线程上运行。
不幸的是,我不能在我的真实代码中使用它作为一种解决方法 - 我尝试让UI线程在工作线程执行之前调用RaiseCanExecuteChanged,但它没有帮助。
是否有任何理由让RaiseCanExecuteChanged以这种方式行事?任何修复或解决方法?
答案 0 :(得分:1)
您在UI线程上创建TestCommand并尝试在单独的线程上访问它。你不能这样做。如果你想要做的只是提升can执行,那么只需等待Task.Run然后调用它。
public MainWindowViewModel()
{
TestCommand = new DelegateCommand(Test, CanTest);
ActionCommand = new DelegateCommand(async () =>
{
await Task.Run(() =>
{
Thread.Sleep(1000);
});
TestCommand.RaiseCanExecuteChanged();
});
}