Hinweis: Der Code in dieser Frage ist Teil von deSleeper, wenn Sie die vollständige Quelle möchten.Asynchrone WPF-Befehle
Eines der Dinge, die ich von Befehlen wollte, war ein gebackenes Design für asynchrone Operationen. Ich wollte, dass die Schaltfläche während der Ausführung des Befehls deaktiviert und nach Abschluss wieder ausgeführt wurde. Ich wollte, dass die eigentliche Arbeit in einem ThreadPool-Arbeitselement ausgeführt wird. Und schließlich wollte ich eine Möglichkeit haben, mit Fehlern umzugehen, die während der asynchronen Verarbeitung aufgetreten sind.
Meine Lösung war ein 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;
}
}
so ist die Frage: Ist das alles nötig? Ich habe bemerkt, eingebaute asynchrone Unterstützung für die Datenbindung, also warum Befehlsausführung nicht? Vielleicht hängt es mit der Parameterfrage zusammen, die meine nächste Frage ist.
Eines der Dinge, die hier ein Problem ist, dass das normale Design für CanExecute ist, wo command- spezifische Logik ist da. Z.B. UndoCommand überprüft möglicherweise, ob ein UndoStack vorhanden ist. Die einzige Logik, die Sie hier haben, ist, ob sie bereits ausgeführt wird oder nicht. –
Beachten Sie, dass CanExecute virtuell ist. In diesem Muster überschreibe ich es und rufe die Basis zuerst auf, um eine befehlsspezifische Logik bereitzustellen. – nedruod