异步WPF命令
时间:2020-03-06 14:54:21 来源:igfitidea点击:
注意:如果我们需要完整的源代码,则此问题中的代码是deSleeper的一部分。
我想从命令中得到的一件事是异步操作的烘焙设计。我希望在执行命令时禁用该按钮,并在完成后返回。我希望在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; } }