Async command execution in MVVM light

杀马特。学长 韩版系。学妹 提交于 2019-12-23 09:37:27

问题


I am wondering why is MVVM light missing command with async execution? I believe there are many cases where this could be useful, so let me name one.

Lets say that our UI contains one container that contains multiple screens. User can close a particular screen, or a container with multiple screens. Lets say that a user has issued a close command on the container. Container in return invokes close command on each screen, and it needs to wait for screen to be closed. This in practice can means validating data. saving, etc. For this reason we need to issue an async call to keep the UI from becoming unresponsive, and also we need to wait for task to complete, in order to continue.

So, if we have something like this in Command

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

}

We could also expose additional method on screen, but in my opinion it should be task of RelayCommand, since it already exist there.

Or there is a different methodology to handle such scenario?


回答1:


Probably because there are many different ways of doing it; I describe a few approaches in my MSDN article on the subject.

Asynchronous lifetime commands are especially tricky. Something like a "close" command must be carefully considered. Is there some indication that a close is in progress? What happens if the user closes more than once ("close" in particular can often be initiated by an OS or another app even if a "close button" is disabled)?




回答2:


I found this being in some ways a solution to making async commands in MVVM Light. If fact it overwrap a async method with Task.Run. Our wrapped method has to verify if it not executed twice, and catches errors from lower async executions.

    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;
            });
        }
    }


来源:https://stackoverflow.com/questions/27699237/async-command-execution-in-mvvm-light

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!