在进行一些密集计算(C#)之前,请等待多个快速属性更改事件

本文关键字:等待 事件 属性 之前 计算 | 更新日期: 2023-09-27 18:24:38

我对这个问题有一个特定的场景,但一个好的通用解决方案应该适用于许多情况:

我有一个WPF ItemsControl,其项的IsSelected属性是绑定到视图模型中相应属性的数据。然后,我有一个计算密集型例程,它(在后台线程上)在所选项目上运行。问题是,如果我在一个项目的IsSelected属性发生更改时触发计算密集型任务,那么当同时选择多个项目时,计算密集型的任务会为每个选择的项目运行一次,而不是在所有项目都被选择后仅运行一次,因此,它最终占用的处理器时间明显多于实际需要的时间。

IEnumerable<MyObject> items;
...
void IsSelectedPropertyChangedListener(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "IsSelected")
        DoSomeIntensiveCalculation(items.Where(t=>t.IsSelected));
}
void DoSomeIntensiveCalculation(IEnumerable<MyObject> itemsToCalculate)
{
    ...
}

当然,我可以注册ItemsControl的SelectionChanged事件并触发它,因为即使选择了多个项目,每次选择更改也只调用一次,但这有点违反MVVM,而且还有其他情况可以应用通用解决方案,这就不容易解决了。(如果你有充分的理由解释为什么在这种特殊的情况下我应该这样做,因为这比任何其他选择都好,我愿意听)

我能想到的另一个例子是,也许你有一个ObservableCollection,每次它发生变化时,你都想计算一些困难的东西。当然,您会注册CollectionChanged事件来触发计算,但假设某个事件同时向集合中添加了大量项,那么一旦添加了所有项,您实际上只需要进行一次计算,对添加的每个项进行计算将大大降低性能。

如果另一个实例已经开始运行,我可以阻止密集型任务的运行,只需设置一个标志,让它在完成时再运行一次,这将导致它只运行两次,即使一次选择了很多东西,但这仍然比真正必要的多了一次。

每次启动新的任务时,我都可以杀死已经在运行的任务实例,但这需要向计算任务添加大量代码,以便在请求时正常停止。它也不适用于我无法控制密集任务的情况(即,它在第三方库中,并且没有提供优雅的停止机制)。

在进行一些密集计算(C#)之前,请等待多个快速属性更改事件

不能100%确定你在问什么,但这里有一些想法:

  1. 使用任务并行库。任务管理器将决定是否启动线程
  2. 使用阻塞队列
  3. 重新设计界面以具有计算按钮
  4. 缓存第一次计算后的结果