c# - 确保异步方法可以更新非线程安全集合的最佳方法是什么?

标签 c# wpf async-await

我正在进行异步调用,最终将更新 GUI 中的集合。异步调用是通过这样的委托(delegate)命令完成的:

StartDoingUsefulStuffCommand = new DelegateCommand(() => Task.Run(() => StartDoingUsefulStuff()));

public async Task StartDoingUsefulStuff()
{
    try
    {
        await some method
        do something else
        MyCollection.Clear();
        ...
        ...
    }
    catch (Exception e)
    {
       // handle exception
    }
}

最终 StartDoingUsefulStuff 方法想要更新一个集合,导致这个异常,因为另一个线程试图更新一个集合:

A first chance exception of type 'System.NotSupportedException' occurred in PresentationFramework.dll

Additional information: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

我找到了一个解决方案:在当前 SynchronizationContext 中运行任务:

Task.Factory.StartNew(() => StartDoingUsefulStuff(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

这会很好地工作,但对我来说,每次从 XAML 调用命令时都执行所有这些操作似乎很乏味。您对我目前的解决方案有何看法/最佳做法是什么?

最佳答案

还有一种更简单的修复方法。在初始化 Collection 的构造函数中,只需在初始化后添加以下行。

BindingOperations.EnableCollectionSynchronization(MyCollection,_lock); 其中 _lock 是一个私有(private)静态对象。那时您不必再在命令中处理线程安全问题。然后您可以安全地使用 await Task.Run

关于c# - 确保异步方法可以更新非线程安全集合的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20210793/

相关文章:

c# - 构建仅包含字段名称的 linq 表达式

c# - 如何通过单击浏览器的后退按钮获得相同的页面

c# - 限制向 ToolStrip 添加控件

wpf - Xaml 绑定(bind)中的切换(选择)语句?

wpf - WPF 样式中 IsMouseOver 和 IsHighlighted 的区别

javascript - 使用 babel 将异步函数与装饰器绑定(bind)

c# - DNN 6 模块 - 如何利用异步调用

wpf - 鼠标悬停时如何更改 TabItem 颜色?

c# - Async/Await 是否使用 Task.Run 异步启动新线程?

C# TPL 以并行方式调用任务并异步创建新文件