【问题标题】:Async command execution in MVVM lightMVVM light 中的异步命令执行
【发布时间】:2015-02-26 06:01:57
【问题描述】:

我想知道为什么 MVVM light 缺少异步执行命令?我相信这在很多情况下都有用,所以让我举一个例子。

假设我们的 UI 包含一个包含多个屏幕的容器。用户可以关闭特定屏幕或具有多个屏幕的容器。假设用户对容器发出了关闭命令。容器反过来在每个屏幕上调用关闭命令,它需要等待屏幕关闭。这在实践中可能意味着验证数据。保存等。出于这个原因,我们需要发出异步调用以防止 UI 变得无响应,并且我们还需要等待任务完成才能继续。

所以,如果我们在 Command 中有这样的东西

public RelayCommand CloseCommand
{
    get { return _closeCommand ?? _closeCommand = new RelayCommand( async () =>
    {
        foreach (var screen in Screens)
        {
            if (!await screen.CloseCommand.ExecuteAsync(null))
            {
                // do something
            }
        }
    }) }

}

我们也可以在屏幕上公开其他方法,但我认为它应该是 RelayCommand 的任务,因为它已经存在。

或者有不同的方法来处理这种情况?

【问题讨论】:

    标签: c# mvvm mvvm-light


    【解决方案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 的答案和cmets 和/或至少观看youtu.be/J0mcYVxJEl0 以了解如何执行此类操作。
    【解决方案2】:

    可能是因为有很多不同的方法;我在my MSDN article on the subject 中描述了一些方法。

    异步生命周期命令特别棘手。必须仔细考虑诸如“关闭”命令之类的东西。是否有迹象表明正在关闭?如果用户多次关闭会发生什么(尤其是“关闭”通常可以由操作系统或其他应用启动,即使“关闭按钮”被禁用)?

    【讨论】:

    • 这是否使用 MVVM Light?
    • 我看不到如何将它应用到 MVVM Light,specifically 如何在视图模型的构造函数中从文件(即不可避免的异步作业)加载数据,以便页面是可混合的。我会继续思考的。
    • @dumbledad:它应该可以与 MVVM Light 或任何其他框架一起正常工作。你遇到的问题是你需要它 Blendable,我不知道它有什么限制。
    猜你喜欢
    • 2015-08-24
    • 2016-02-03
    • 1970-01-01
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多