-
02-07-2019 - |
题
注意 :此问题中的代码是 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;
}
}
其他提示
正如我在你的另一个问题中回答的那样,你可能仍然希望同步绑定到它,然后异步启动命令。这样你就可以避免现在遇到的问题。
不隶属于 StackOverflow