Hinweis : Der Code in dieser Frage ist Teil von deSleeper wenn Sie die vollständige Quelle benötigen.
Eines der Dinge, die ich von den Befehlen wollte, war ein gebackenes Design für asynchrone Operationen. Ich wollte, dass die gedrückte Schaltfläche deaktiviert wird, während der Befehl ausgeführt wird, und dass sie zurückkommt, wenn er abgeschlossen ist. Ich wollte, dass die eigentliche Arbeit in einem ThreadPool-Workitem ausgeführt wird. Und schließlich wollte ich eine Möglichkeit haben, Fehler zu behandeln, die während der asynchronen Verarbeitung auftreten.
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;
}
}
Die Frage ist also: Ist das alles notwendig? Ich habe bemerkt, in asynchrone Unterstützung für Datenbindung gebaut, warum also nicht Befehlsausführung? Vielleicht ist es im Zusammenhang mit dem Parameter Frage, die meine nächste Frage ist.
0 Stimmen
Eines der Probleme hier ist, dass der normale Entwurf für CanExecute eine befehlsspezifische Logik enthält. Z.B. könnte UndoCommand prüfen, ob es einen UndoStack gibt. Die einzige Logik, die Sie hier haben, ist, ob der Befehl bereits ausgeführt wird oder nicht.
0 Stimmen
Beachten Sie, dass CanExecute virtuell ist. In diesem Muster setze ich es außer Kraft und rufe zuerst base auf, um eine befehlsspezifische Logik bereitzustellen.