Frage

Hinweis : Der Code in dieser Frage ist ein Teil von deSleeper , wenn Sie wollen, dass die volle Quelle.

Eines der Dinge, die ich aus Befehlen wollte, war ein Back Design für asynchrone Operationen. Ich wollte die Taste gedrückt zu deaktivieren, während der Befehl ausgeführt wurde, und kommen zurück, wenn Sie fertig sind. Ich wollte die eigentliche Arbeit in einem Threadpool Workitem durchgeführt werden. Und schließlich wollte ich einen Weg, um alle Fehler zu behandeln, die während der asynchronen Verarbeitung aufgetreten.

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 in asynchroner Unterstützung für Datenbindung, also warum nicht befehlen Ausführung gebaut bemerkt? Vielleicht ist es auf den Parameter Frage zusammen, die meine nächste Frage ist.

War es hilfreich?

Lösung

Ich habe in der Lage Sie die Originalprobe weiter zu verfeinern und einige Ratschläge für jemand anderes in ähnlichen Situationen ausgeführt wird.

Zuerst prüfen, ob Background die Bedürfnisse erfüllen. Ich noch AsyncCommand oft verwenden Sie die automatische Sperrfunktion zu bekommen, aber wenn viele Dinge könnten mit Background erfolgen.

Aber durch Umwickeln Background stellt AsyncCommand Befehl wie Funktionalität mit asynchronem Verhalten (Ich habe auch ein Blog-Eintrag zu diesem Thema )

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;
    }
}

Andere Tipps

Wie ich in der anderen Frage beantwortet, Sie wollen wahrscheinlich noch diese binden, synchron und dann die Befehle asynchron starten. Auf diese Weise kann die Probleme vermeiden Sie jetzt haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top