Как вызвать асинхронный метод при нажатии кнопки с использованием MVVM? - PullRequest
1 голос
/ 30 января 2020

Я сейчас искал способ привязать команду к кнопке, которая должна вызывать функцию в моей ViewModel, которая имеет асинхронный характер c и которая должна начать вызов и иметь возможность отменить вызов. Я взглянул на учебники Стивена Клири и попытался преобразовать их в мои потребности, хотя диспетчер команд не существует в текущем контексте в AsyncCommandBase, и когда вы смотрите на его код проекта git, он не похож на тот, что в его учебник ... Я понятия не имею, где продолжать получать мой ответ, поэтому здесь мы go. У меня есть ViewModel, которая должна запускать функцию asyn c и которая должна запускаться нажатием кнопки? Есть ли способ сделать это без написания новой библиотеки? Я сделал интерфейс, который выглядит следующим образом ...

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 голосов
/ 30 января 2020

Не понимаю, зачем вам нужно создавать асин c версию вашего RelayCommand. Вы можете просто запустить метод asyn c, когда выполняется команда, которая прослушивает токен отмены. Что-то вроде:

Ваша команда: 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();
    }

Я рекомендую использовать подходящую библиотеку, такую ​​как МВВМ Лайт. Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...