防止多次执行ReactiveCommand(CreateAsyncTask)

时间:2015-11-12 16:43:52

标签: c# wpf system.reactive reactiveui

是否可以防止多次执行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 个答案:

答案 0 :(得分:1)

我下载了您的示例应用程序,并且能够修复它。这是我的2美分:

1)我在命令创建中取出了Rx.TaskpoolScheduler参数。这告诉它使用该调度程序提供结果,我认为您希望坚持在UI线程上提供结果。

2)由于通过进行此更改,您现在正在UI线程上运行订阅逻辑,因此您无需处理所有调用。您可以直接访问该集合:

this.LoadCommand.Subscribe(dataCollection =>
                                      {
                                          DataCollection.Clear();
                                          DataCollection.AddRange(dataCollection);
                                      });

只进行这两项更改就会使其“正常工作”。

我不是专家,但我认为发生的事实是你所拥有的实际ReactiveCommand“LoadCommand”会立即返回并在各种TaskPool线程上提供结果。所以它永远不会允许Command本身内的并发,这是设计的。然而,我认为订阅,因为每个人都在一个不同的线程进入,同时发生(比赛)。所以所有的清除都发生了,然后是所有的补充。

通过在同一个线程上订阅和处理所有内容,您可以避免这种情况,如果您可以在UI线程上进行管理,则无需涉及调用Dispatcher。

此外,在这种特殊情况下,使用调度程序上的Invoke优先级DispatcherPriority.Background似乎以非串行方式执行,不确定顺序,但它似乎完成所有清除,然后以相反的顺序添加(我递增它们以便我可以告诉它是哪个调用)。所以肯定有一些东西可以说。 FWIW将优先级更改为DispatcherPriority.Send使其保持连续并显示“预期”行为。话虽如此,如果可以的话,我仍然希望完全避免调用Dispatcher。