DelegateCommand 异步等待与 Task.Run UI 锁定

DelegateCommand async await vs Task.Run UI locking

我希望我的 UI 在我点击我的按钮时显示一个加载叠加层。

选项 1

MyCommand = new DelegateCommand(() => Task.Run(MyLongRunningTask);

private async Task MyLongRunningTask() {
    IsLoading = true;
    Thread.Sleep(5000);
    IsLoading = false;
}

选项 2

MyCommand = new DelegateCommand(MyLongRunningMethod);

private async void MyLongRunningMethod() {
    IsLoading = true;
    Thread.Sleep(5000);
    IsLoading = false;
}

选项 1 有效,选项 2 无效。我对这种情况很好,虽然我不明白为什么。 但我真的很想避免将每次执行都包装到 () => Task.Run(...).

由于 async void 似乎不是一个好主意,我想继续使用任务。但我想缩短语法,所以我疯狂地尝试,但我不知道如何将 () => Task.Run(..) 放在方法中或从 DelegateCommand 派生的 class 中。

为什么编译不了?

    private DelegateCommand GetAsyncCommand(Task t)
    {
        return new DelegateCommand(() => Task.Run(t));
    }

任何与此类似的事情都会导致编译时错误,或者我不得不调用

MyCommand = GetAsyncCommand(MyLongRunningTask());

由于 () 大括号,它会在实例化时立即执行我的任务。

这让我觉得很费解。如果我必须将我所有的 运行 长任务包装到这个结构中,为什么我不能构建一个更智能的命令来为我完成任务?

编辑:我只是注意到选项 1 可能不会锁定 UI,但它会吞下非常可怕的异常。

如何设置不阻塞 UI 并正常抛出任何异常的命令?

Thread.Sleep() 正在锁定当前线程,无论它在哪里:在同步或异步方法中。异步方法有另一种暂停执行的方法 - await Task.Delay().

async 不对 Threading 负责,async 实现了一个 state mashine 来执行您的代码,将代码异步拆分为可等待的部分。 Task 负责线程。

替换

Thread.Sleep(5000);

await Task.Delay(5000);

请注意 async void 是不好的做法。 Look.