3

下面的示例使用 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 线程调用此方法也没有问题。

更奇怪的是,如果首先引发 TestCommand,那么 ActionCommand 开始正常工作。我已经检查过了,Task.Run 块中的代码在所有情况下都在非 UI 线程上运行。

不幸的是,我不能在我的真实代码中使用它作为解决方法——我尝试在工作线程执行之前让 UI 线程调用 RaiseCanExecuteChanged,但它没有帮助。

RaiseCanExecuteChanged 有什么理由这样做吗?任何修复或解决方法?

4

1 回答 1

1

您正在 UI 线程上创建 TestCommand 并尝试在单独的线程上访问它。你不能那样做。如果您只想提高可执行权限,则只需等待 Task.Run 然后调用它。

    public MainWindowViewModel()
    {
        TestCommand = new DelegateCommand(Test, CanTest);

        ActionCommand = new DelegateCommand(async () => 
        {
            await Task.Run(() =>
            {
                Thread.Sleep(1000);
            });

            TestCommand.RaiseCanExecuteChanged();
        });
    }
于 2015-11-11T22:30:05.493 回答