使用MVVM按下按钮时如何调用异步方法?

时间:2020-01-30 14:29:11

标签: c# mvvm

我现在一直在寻找一种将命令绑定到按钮的方法,该按钮应该在我的ViewModel中提示一个异步功能,并应该启动该调用并能够取消该调用。我查看了Stephen Cleary的教程,并尝试将它们转换为我的需求,尽管在当前上下文中AsyncCommandBase中不存在命令管理器,当您查看他的git项目代码时,它与他的教程中的代码完全不同...我不知道从哪里继续得到我的答案,所以我们开始吧。我有一个ViewModel应该运行一个异步函数,并且应该通过单击按钮来运行?有什么方法可以在不编写新库的情况下完成此工作?我制作了一个看起来像这样的界面...

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using System.Threading.Tasks; 

    namespace Data
    {
        public interface IAsyncCommand : ICommand
        {
            Task ExcecuteAsync(Object parameter); 
        }
    }

和基本的Commandclass像这样

using System;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Data
{
    /// <summary>
    /// An async command that implements <see cref="ICommand"/>, forwarding <see cref="ICommand.Execute(object)"/> to <see cref="IAsyncCommand.ExecuteAsync(object)"/>.
    /// </summary>
    public abstract class AsyncCommandBase : IAsyncCommand
    {
        /// <summary>
        /// The local implementation of <see cref="ICommand.CanExecuteChanged"/>.
        /// </summary>
        private readonly ICanExecuteChanged _canExecuteChanged;

        /// <summary>
        /// Creates an instance with its own implementation of <see cref="ICommand.CanExecuteChanged"/>.
        /// </summary>
        protected AsyncCommandBase(Func<object, ICanExecuteChanged> canExecuteChangedFactory)
        {
            _canExecuteChanged = canExecuteChangedFactory(this);
        }

        /// <summary>
        /// Executes the command asynchronously.
        /// </summary>
        /// <param name="parameter">The parameter for the command.</param>
        public abstract Task ExecuteAsync(object parameter);

        /// <summary>
        /// The implementation of <see cref="ICommand.CanExecute(object)"/>.
        /// </summary>
        /// <param name="parameter">The parameter for the command.</param>
        protected abstract bool CanExecute(object parameter);

        /// <summary>
        /// Raises <see cref="ICommand.CanExecuteChanged"/>.
        /// </summary>
        protected void OnCanExecuteChanged()
        {
            _canExecuteChanged.OnCanExecuteChanged();
        }

        event EventHandler ICommand.CanExecuteChanged
        {
            add { _canExecuteChanged.CanExecuteChanged += value; }
            remove { _canExecuteChanged.CanExecuteChanged -= value; }
        }

        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute(parameter);
        }

        async void ICommand.Execute(object parameter)
        {
            await ExecuteAsync(parameter);
        }
    }
}

该链接指向他的教程,如果需要,请告诉我,我会尽快发送他的git代码! :D

https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/april/async-programming-patterns-for-asynchronous-mvvm-applications-commands

1 个答案:

答案 0 :(得分:0)

我不明白为什么需要创建RelayCommand的异步版本。您可以在命令执行时仅运行一个异步方法来侦听取消令牌。像这样:

您的命令:public ICommand DoSomethingCommand { get; set; }

在以下位置实例化命令:DoSomethingCommand = new RelayCommand(DoSomething);

还有DoSomething方法的示例:

private async void DoSomething()
{
    using (var cancellationToken = new CancellationTokenSource())
    {
        await Task.Run(() => 
        {
            for(i = 0; i < 100; i++)
            {
                if (cancellationToken.IsCancellationRequested) break;
                //Here's where something is done.
            }
        });
    }
}

正常绑定:<Button Content="Do Something" Command="{Binding DoSomethingCommand}"/>

只要您需要它,就可以使用以下简单的RelayCommand

public class RelayCommand : ICommand
    {
        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            CommandManager.RequerySuggested += (s, e) => CanExecuteChanged(s, e);
            CanExecuteDelegate = canExecute;
            ExecuteDelegate = execute;
        }
        public RelayCommand(Action execute) : this(execute, () => true) { }
        public event EventHandler CanExecuteChanged = delegate { };
        public Func<bool> CanExecuteDelegate { get; set; }
        public Action ExecuteDelegate { get; set; }
        public bool CanExecute(object parameter) => CanExecuteDelegate();
        public void Execute(object parameter) => ExecuteDelegate();
    }

我确实建议使用适当的库,例如MVVM Light。希望这会有所帮助。