您当前的位置: 首页 > 

君子居易

暂无认证

  • 0浏览

    0关注

    210博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

WPF 在 ObservableCollection 中处理跨线程

君子居易 发布时间:2022-07-09 14:16:22 ,浏览量:0

我认为 WPF 中最好的事情之一是引入ObservableCollection。有了这个类,数据绑定变得轻而易举,开发人员不再需要编写自定义代码来获得与 INotifyPropertyChanged 相同的效果。

我今天在玩一些多线程代码来更新我的ObservableCollection并遇到了一个异常,并显示以下消息“这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection。

从一个集合中得到一个跨线程异常是很奇怪的,但如果你仔细想想,它是有道理的。ObservableCollection通常用于 WPF 数据绑定,并在其内容被修改时在内部引发CollectionChanged事件。如果在不同线程上添加项目,这也意味着在该不同线程上引发CollectionChanged事件,并且 WPF 的数据绑定控件将尝试根据该更改进行刷新。我们都知道 UI 控件的跨线程是一个很大的禁忌,一个控件只能在创建它的同一个线程上访问,即 UI 线程。现在能看到联动了吗?为了克服这个问题,我们只需要在ObservableCollection返回到 WPF 术语中的正确线程或 Dispatcher。

这是我编写的用于编组的代码片段。此类将在其构造函数中获取对当前 Dispatcher(当前线程)的引用,因此您需要确保在同一线程上创建 ObservableCollection。这通常不是问题,除非您在不同的线程上创建 ObservableCollection。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class ObservableCollectionMarshaler
{
    public Dispatcher Dispatcher { get; set; }
 
    public ObservableCollectionMarshaler()
    {
        Dispatcher = Dispatcher.CurrentDispatcher;
    }
 
    public void AddItem(ObservableCollection oc, T item)
    {
        if (Dispatcher.CheckAccess())
        {
            oc.Add(item);
        }
        else
        {
            Dispatcher.Invoke(new Action(t => oc.Add(t)), DispatcherPriority.DataBind, item);
        }
    }
 
    public void RemoveItem(ObservableCollection oc, T item)
    {
        if (Dispatcher.CheckAccess())
        {
            oc.Remove(item);
        }
        else
        {
            Dispatcher.Invoke(new Action(t => oc.Remove(t)), DispatcherPriority.DataBind, item);
        }
    }
 
    public void Clear(ObservableCollection oc)
    {
        if (Dispatcher.CheckAccess())
        {
            oc.Clear();
        }
        else
        {
            Dispatcher.Invoke(new Action(() => oc.Clear()), DispatcherPriority.DataBind);
        }
    }
}

如果在构造函数中获取 Dispatcher.CurrentDispatcher 对您来说太不安全,您始终可以在构造函数参数中传入 Dispatcher。

如果您要进行大量异步处理,为 ObservableCollection 创建一个 Wrapper 类来处理编组逻辑可能是一个好主意。希望这对您有所帮助。

关注
打赏
1660814979
查看更多评论
立即登录/注册

微信扫码登录

0.0358s