MVVM light中的异步命令执行

7
我想知道为什么MVVM Light没有异步执行命令?我相信有很多情况下这会很有用,让我举个例子。
假设我们的UI包含一个容器,其中包含多个屏幕。用户可以关闭特定的屏幕或包含多个屏幕的容器。假设用户已经在容器上发出了关闭命令。容器会调用每个屏幕上的关闭命令,并且需要等待屏幕关闭。实际上,这可能意味着验证数据、保存等操作。因此,我们需要发出异步调用以防止UI变得无响应,并且我们需要等待任务完成,才能继续进行。
所以,如果我们在命令中有这样的内容:
public RelayCommand CloseCommand
{
    get { return _closeCommand ?? _closeCommand = new RelayCommand( async () =>
    {
        foreach (var screen in Screens)
        {
            if (!await screen.CloseCommand.ExecuteAsync(null))
            {
                // do something
            }
        }
    }) }

}

我们也可以在屏幕上暴露其他方法,但在我看来,这应该是RelayCommand的任务,因为它已经存在于那里。
或者有一种不同的方法来处理这种情况吗?
2个回答

5

可能是因为有许多不同的做法; 我在 我的MSDN文章中描述了几种方法

异步生命周期命令特别棘手。像“关闭”命令这样的东西必须仔细考虑。是否有某些指示表明正在进行关闭操作?如果用户关闭多次会发生什么情况(尤其是“关闭”按钮被禁用时,操作系统或另一个应用程序通常也可以启动“关闭”)?


这个使用MVVM Light吗? - dumbledad
我不知道如何将其应用于MVVM Light,尤其是如何在视图模型的构造函数中从文件加载数据(即不可避免的异步作业),以使页面可混合。我会继续思考。 - dumbledad
@dumbledad: 它应该可以与MVVM Light或任何其他框架很好地配合使用。你遇到的问题是你需要它可混合,而我不清楚这会带来什么限制。 - Stephen Cleary

-1

我发现这是在MVVM Light中实现异步命令的一种解决方案。 事实上,它使用Task.Run覆盖了一个异步方法。我们的包装方法必须验证它没有被执行两次,并捕获来自较低异步执行的错误。

    private bool isLoading;

    public bool IsLoading
    {
        get { return isLoading; }
        set
        {
            if (value != isLoading)
            {
                Set(ref isLoading, value);
                //Used to refresh Commands CanExecute laying on IsLoading
                CommandManager.InvalidateRequerySuggested();
            }
        }
    }

    private RelayCommand loadCommand;

    public RelayCommand LoadCommand
    {
        get
        {
            return loadCommand ?? (loadCommand = new RelayCommand(
                () => Task.Run(LoadAsync),
                () => !IsLoading
            ));
        }
    }

    private async Task LoadAsync()
    {
        //Prevents double execution in case of many mouse clicks on button
        if (IsLoading)
        {
            return;
        }

        //Assignments which need to be done on UI tread 
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            IsLoading = true;
        });

        try
        {
            list = await service.LoadAsync();
            ...
        }
        catch (Exception e)
        {
            ...
        }
        finally
        {
            DispatcherHelper.CheckBeginInvokeOnUI(() =>
            {
                IsLoading = false;
            });
        }
    }

你真的做错了。既不推荐使用DispatcherHelper,也不需要使用try/catch,甚至没有一个被建议。我强烈建议你阅读@Stephen Cleary的答案和评论,或者至少观看https://youtu.be/J0mcYVxJEl0,了解如何处理这样的事情。 - Yoda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接