是否可以防止多次执行ReactiveCommand。
这是我使用的"简单"代码:
创建命令:
this.LoadCommand = ReactiveCommand.CreateAsyncTask(
async _ => await this._dataService.Load(),
RxApp.TaskpoolScheduler);
在我将订阅添加到命令后:
this.LoadCommand.Subscribe(assets => ...);
最后,我执行命令:
this.LoadCommand.ExecuteAsyncTask();
如果我在多个位置多次调用ExecuteAsyncTask,我希望任何后续调用都等待第一个调用完成。
编辑:以下是Subscribe方法的完整代码:
this.LoadCommand.Subscribe(assets =>
{
Application.Current.Dispatcher.Invoke(
DispatcherPriority.Background,
new Action(() => this.Assets.Clear()));
foreach (Asset asset in assets)
{
Application.Current.Dispatcher.Invoke(
DispatcherPriority.Background,
new Action<Asset>(a =>
{
this.Assets.Add(a);
}), asset);
}
});
谢谢,
阿德里安。
我下载了您的示例应用程序,并能够修复它
1) 我在您的命令创建中取出了Rx.TaskpoolScheduler
参数。这告诉它使用该调度程序传递结果,我认为您应该坚持在UI线程上传递结果。
2) 由于通过进行此更改,您现在正在UI线程上运行Subscribe逻辑,因此不需要处理所有的Invoking。您可以直接访问收藏:
this.LoadCommand.Subscribe(dataCollection =>
{
DataCollection.Clear();
DataCollection.AddRange(dataCollection);
});
仅仅做了这两个改变就让它"工作"了。
我不是专家,但我认为实际发生的情况是,您拥有的实际ReactiveCommand"LoadCommand"立即返回并在各种TaskPool线程上传递结果。因此,它永远不会允许在命令本身中并发,这是经过设计的。然而,我认为订阅是同时发生的(竞争),因为每个订阅都来自不同的线程。所以所有的清除都发生了,然后所有的添加都发生了。
通过在同一个线程上订阅和处理所有内容,可以避免这种情况,如果可以在UI线程上管理它,则不需要调用Dispatcher。
此外,在这种特殊情况下,在优先级为DispatcherPriority.Background
的Dispatcher上使用Invoke似乎以非串行方式执行事情,不确定确切的顺序,但它似乎以相反的顺序执行所有清除,然后添加(我增加了它们,这样我就可以判断是哪个调用)。因此,肯定有一些话要说。FWIW将优先级更改为DispatcherPriority.Send
,使其保持串行并显示"预期"行为。话虽如此,如果可以的话,我仍然倾向于完全避免调用Dispatcher。