DrG*_*iff 17 wpf asynchronous mvvm task-parallel-library async-await
我一直在关注Stephen Cleary在MSDN杂志(异步MVVM应用程序模式)中的一系列相当优秀的文章,并一直IAsyncCommand
在"hello world"风格的应用程序中使用他的模式.
但是,他没有解决的一个领域是当需要传入命令参数时(使用此模式).对于一个简单的示例,请考虑身份验证,其中出于安全原因,密码控件可能不受数据限制.
我想知道是否有人设法让他的AsyncCommand
参与工作,如果是这样,他们会分享他们的发现吗?
C8H*_*4O2 16
让Stephen Cleary的IAsyncCommand模式使用在生成要执行的Task时获取参数的函数只需要对他的AsyncCommand类和静态辅助方法进行一些调整.
从上面链接中的AsyncCommand4示例中找到的类开始,让我们修改构造函数以获取一个函数,该函数包含一个参数(类型为对象 - 这将是命令参数)的输入,以及一个CancellationToken并返回一个Task.我们还需要在ExecuteAsync方法中进行一次更改,以便在执行命令时将参数传递给此函数.我创建了一个名为AsyncCommandEx的类(如下所示),用于演示这些更改.
public class AsyncCommandEx<TResult> : AsyncCommandBase, INotifyPropertyChanged
{
private readonly CancelAsyncCommand _cancelCommand;
private readonly Func<object, CancellationToken, Task<TResult>> _command;
private NotifyTaskCompletion<TResult> _execution;
public AsyncCommandEx(Func<object, CancellationToken, Task<TResult>> command)
{
_command = command;
_cancelCommand = new CancelAsyncCommand();
}
public ICommand CancelCommand
{
get { return _cancelCommand; }
}
public NotifyTaskCompletion<TResult> Execution
{
get { return _execution; }
private set
{
_execution = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public override bool CanExecute(object parameter)
{
return (Execution == null || Execution.IsCompleted);
}
public override async Task ExecuteAsync(object parameter)
{
_cancelCommand.NotifyCommandStarting();
Execution = new NotifyTaskCompletion<TResult>(_command(parameter, _cancelCommand.Token));
RaiseCanExecuteChanged();
await Execution.TaskCompletion;
_cancelCommand.NotifyCommandFinished();
RaiseCanExecuteChanged();
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
private sealed class CancelAsyncCommand : ICommand
{
private bool _commandExecuting;
private CancellationTokenSource _cts = new CancellationTokenSource();
public CancellationToken Token
{
get { return _cts.Token; }
}
bool ICommand.CanExecute(object parameter)
{
return _commandExecuting && !_cts.IsCancellationRequested;
}
void ICommand.Execute(object parameter)
{
_cts.Cancel();
RaiseCanExecuteChanged();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void NotifyCommandStarting()
{
_commandExecuting = true;
if (!_cts.IsCancellationRequested)
return;
_cts = new CancellationTokenSource();
RaiseCanExecuteChanged();
}
public void NotifyCommandFinished()
{
_commandExecuting = false;
RaiseCanExecuteChanged();
}
private void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新静态AsyncCommand辅助类以使创建命令参数感知IAsyncCommands更容易也是有帮助的.要处理执行或不执行命令参数的函数的可能组合,我们将使方法数量加倍,但结果也不错:
public static class AsyncCommandEx
{
public static AsyncCommandEx<object> Create(Func<Task> command)
{
return new AsyncCommandEx<object>(async (param,_) =>
{
await command();
return null;
});
}
public static AsyncCommandEx<object> Create(Func<object, Task> command)
{
return new AsyncCommandEx<object>(async (param, _) =>
{
await command(param);
return null;
});
}
public static AsyncCommandEx<TResult> Create<TResult>(Func<Task<TResult>> command)
{
return new AsyncCommandEx<TResult>((param,_) => command());
}
public static AsyncCommandEx<TResult> Create<TResult>(Func<object, Task<TResult>> command)
{
return new AsyncCommandEx<TResult>((param, _) => command(param));
}
public static AsyncCommandEx<object> Create(Func<CancellationToken, Task> command)
{
return new AsyncCommandEx<object>(async (param, token) =>
{
await command(token);
return null;
});
}
public static AsyncCommandEx<object> Create(Func<object, CancellationToken, Task> command)
{
return new AsyncCommandEx<object>(async (param, token) =>
{
await command(param, token);
return null;
});
}
public static AsyncCommandEx<TResult> Create<TResult>(Func<CancellationToken, Task<TResult>> command)
{
return new AsyncCommandEx<TResult>(async (param, token) => await command(token));
}
public static AsyncCommandEx<TResult> Create<TResult>(Func<object, CancellationToken, Task<TResult>> command)
{
return new AsyncCommandEx<TResult>(async (param, token) => await command(param, token));
}
}
Run Code Online (Sandbox Code Playgroud)
要继续使用Stephen Cleary的示例,您现在可以构建一个AsyncCommand,它接受从Command Parameter传入的对象参数(可以绑定到UI):
CountUrlBytesCommand = AsyncCommandEx.Create((url,token) => MyService.DownloadAndCountBytesAsync(url as string, token));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
8601 次 |
最近记录: |