【发布时间】:2017-04-15 03:23:19
【问题描述】:
我对 Tasks 和 async/await 关键字感到有些困惑。我知道您不应该混合使用异步代码和阻塞代码。或者至少我对混合它们的解释是:
不要从非异步方法调用阻塞 API。所以这是我的问题。
我正在尝试等待一个方法,然后相应地更新 UI。问题是等待异步方法()调用的唯一方法是从内部和异步方法()。
这是一个例子:
private RelayCommand<Options> _executeCommand;
public RelayCommand<Options> ExecuteCommand
{
get
{
return _executeCommand ?? (_executeCommand = new RelayCommand<Options>(async (options) =>
{
Completed = false;
var cancellationTokenSource = new CancellationTokenSource();
await RunValidation(options, cancellationTokenSource.Token);
Completed = true;
}));
}
}
此代码正确运行该方法并等待。问题是我什么时候回来。由于某种原因,在设置 Complete 标志时,依赖于该标志的按钮不会被切换。如果我评论等待代码,那么按钮会正确切换。所以假设我没有在 UI 线程上返回,所以我尝试使用此代码:
private RelayCommand<Options> _executeCommand;
public RelayCommand<Options> ExecuteCommand
{
get
{
return _executeCommand ?? (_executeCommand = new RelayCommand<Options>(async (options) =>
{
Completed = false;
var cancellationTokenSource = new CancellationTokenSource();
var context = TaskScheduler.FromCurrentSynchronizationContext();
await RunValidation(options, cancellationTokenSource.Token).ContinueWith(t => Completed = true, context);
//Completed = true;
}));
}
}
这里是 RunValidation() 方法:
private async Task RunValidation(Options options, CancellationToken token)
{
await _someService.SomAsyncMethod(options, token));
}
如果您注意到,ExecuteCommand 在传递给命令的(选项)参数之前有一个异步关键字。如果我删除了 async 关键字,那么我必须修改对 RunValidation() 方法的调用。我仍然需要它等待,所以这就是我所做的:
private RelayCommand<Options> _executeCommand;
public RelayCommand<Options> ExecuteCommand
{
get
{
return _executeCommand ?? (_executeCommand = new RelayCommand<Options>((options) =>
{
Completed = false;
var context = TaskScheduler.FromCurrentSynchronizationContext();
var cancellationTokenSource = new CancellationTokenSource();
Task.Run(async () => await RunValidation(options, cancellationTokenSource.Token));
Completed = true;
}));
}
}
这段代码的问题是它没有等待。所以我很茫然。
谁能帮我解释一下。我已经在这上面花了 2 多天的时间,我还在这里。
谢谢, 蒂姆
这里是命令按钮的绑定。
private readonly Independent<bool> _completed = new Independent<bool>(true);
public bool Completed
{
get { return _completed; }
set { _completed.Value = value; }
}
private ICommand _doneCommand;
public ICommand DoneCommand
{
get
{
return _doneCommand ?? (_doneCommand = MakeCommand.When(() => Completed).Do(() =>
{
DoSomething();
}));
}
}
private ICommand _cancelCommand;
public ICommand CancelCommand
{
get
{
return _cancelCommand ??
(_cancelCommand = MakeCommand.When(() => !Completed).Do(() => DoSomthingElse()));
}
}
我正在使用 Michael Perry 的 UpdateControls 库中的 MakeCommand 对象。它们包含在 Complete 属性更改时引发 CanExecuteChange 事件的依赖性跟踪。
【问题讨论】:
-
第一段代码是正确的。按钮如何绑定到 Completed 标志?可以观察到吗?
-
由于您的问题是由于通知丢失造成的,并且由于您使用的库应该为您生成通知,因此我建议您使用 UpdateControls 库提出问题。
-
所以我并没有发疯,从表面上看,我做事正确吗?
-
你在 XAML 中的 ExecuteCommand 绑定中设置 IsAsync=true 了吗?
-
我不熟悉那个库,所以可能还有更多事情要做,但是对于普通的 MVVM,您需要在设置 Complete 属性时触发 NotifyPropertyChanged 事件,以便通知绑定到它的任何内容.这只是一个建议,根据设置的内部工作原理,可能不需要。可能会添加它,看看它是否会改变?
标签: c# async-await task