Асинхронные команды WPF
-
02-07-2019 - |
Вопрос
Примечание:Код в этом вопросе является частью Дезодорант если вам нужен полный исходный код.
Одной из вещей, которые я хотел получить от commands, был продуманный дизайн для асинхронных операций.Я хотел, чтобы нажатая кнопка отключалась во время выполнения команды и возвращалась после завершения.Я хотел, чтобы фактическая работа выполнялась в рабочем элементе ThreadPool.И, наконец, мне нужен был способ обработки любых ошибок, которые возникали во время асинхронной обработки.
Моим решением была команда AsyncCommand:
public abstract class AsyncCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public event EventHandler ExecutionStarting;
public event EventHandler<AsyncCommandCompleteEventArgs> ExecutionComplete;
public abstract string Text { get; }
private bool _isExecuting;
public bool IsExecuting
{
get { return _isExecuting; }
private set
{
_isExecuting = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
protected abstract void OnExecute(object parameter);
public void Execute(object parameter)
{
try
{
IsExecuting = true;
if (ExecutionStarting != null)
ExecutionStarting(this, EventArgs.Empty);
var dispatcher = Dispatcher.CurrentDispatcher;
ThreadPool.QueueUserWorkItem(
obj =>
{
try
{
OnExecute(parameter);
if (ExecutionComplete != null)
dispatcher.Invoke(DispatcherPriority.Normal,
ExecutionComplete, this,
new AsyncCommandCompleteEventArgs(null));
}
catch (Exception ex)
{
if (ExecutionComplete != null)
dispatcher.Invoke(DispatcherPriority.Normal,
ExecutionComplete, this,
new AsyncCommandCompleteEventArgs(ex));
}
finally
{
dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() => IsExecuting = false));
}
});
}
catch (Exception ex)
{
IsExecuting = false;
if (ExecutionComplete != null)
ExecutionComplete(this, new AsyncCommandCompleteEventArgs(ex));
}
}
public virtual bool CanExecute(object parameter)
{
return !IsExecuting;
}
}
итак, вопрос заключается в следующем:Необходимо ли все это?Я заметил встроенную асинхронную поддержку привязки данных, так почему бы не выполнить команду?Возможно, это связано с вопросом о параметрах, который является моим следующим вопросом.
Решение
Мне удалось доработать исходный образец и дать несколько советов всем, кто еще сталкивался с подобными ситуациями.
Во-первых, подумайте, удовлетворит ли BackgroundWorker ваши потребности.Я все еще часто использую AsyncCommand, чтобы получить функцию автоматического отключения, но если бы многое можно было сделать с помощью BackgroundWorker.
Но, оборачивая BackgroundWorker, AsyncCommand предоставляет функциональность, подобную команде, с асинхронным поведением (у меня также есть запись в блоге на эту тему)
public abstract class AsyncCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public event EventHandler RunWorkerStarting;
public event RunWorkerCompletedEventHandler RunWorkerCompleted;
public abstract string Text { get; }
private bool _isExecuting;
public bool IsExecuting
{
get { return _isExecuting; }
private set
{
_isExecuting = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
protected abstract void OnExecute(object parameter);
public void Execute(object parameter)
{
try
{
onRunWorkerStarting();
var worker = new BackgroundWorker();
worker.DoWork += ((sender, e) => OnExecute(e.Argument));
worker.RunWorkerCompleted += ((sender, e) => onRunWorkerCompleted(e));
worker.RunWorkerAsync(parameter);
}
catch (Exception ex)
{
onRunWorkerCompleted(new RunWorkerCompletedEventArgs(null, ex, true));
}
}
private void onRunWorkerStarting()
{
IsExecuting = true;
if (RunWorkerStarting != null)
RunWorkerStarting(this, EventArgs.Empty);
}
private void onRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
IsExecuting = false;
if (RunWorkerCompleted != null)
RunWorkerCompleted(this, e);
}
public virtual bool CanExecute(object parameter)
{
return !IsExecuting;
}
}
Другие советы
Как я ответил в вашем другом вопросе, вы, вероятно, все еще хотите привязаться к этому синхронно, а затем запускать команды асинхронно.Таким образом, вы избежите проблем, с которыми сталкиваетесь сейчас.