异步WPF命令 [英] Asynchronous WPF Commands

查看:222
本文介绍了异步WPF命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:此问题中的代码是 deSleeper 如果你想要完整的源代码。

Note: The code in this question is part of deSleeper if you want the full source.

我想要的命令之一是一个烘焙设计的异步操作。我想要按钮在命令执行时禁用,并在完成后回来。我想要在ThreadPool工作项中执行实际工作。最后,我想要一种方法来处理异步处理过程中发生的任何错误。

One of the things I wanted out of commands was a baked design for asynchronous operations. I wanted the button pressed to disable while the command was executing, and come back when complete. I wanted the actual work to be performed in a ThreadPool work item. And lastly, I wanted a way to handle any errors that occurred during the asynchronous processing.

我的解决方案是AsyncCommand:

My solution was an 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 the question is: Is all this necessary? I've noticed built in asynchronous support for data-binding, so why not command execution? Perhaps it's related to the parameter question, which is my next question.

推荐答案

我已经能够优化原始的样本并为遇到类似情况的任何人提供一些建议。

I've been able to refine the original sample down and have some advice for anyone else running into similar situations.

首先,考虑如果BackgroundWorker将满足需求。我仍然使用AsyncCommand经常获得自动禁用功能,但如果许多事情可以用BackgroundWorker完成。

First, consider if BackgroundWorker will meet the needs. I still use AsyncCommand often to get the automatic disable function, but if many things could be done with BackgroundWorker.

但是通过包装BackgroundWorker,AsyncCommand提供命令类似功能的异步行为(我也有此主题的博文

But by wrapping BackgroundWorker, AsyncCommand provides command like functionality with asynchronous behavior (I also have a blog entry on this topic)

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

这篇关于异步WPF命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆