ObservableCollection多个非UI线程访问的方法

69 篇文章 3 订阅

WPF 应用程序可以使用 ItemsControl 或它的一个子类( ListBox 、 DataGrid 、 TreeView 、等 ListView )来显示数据的集合。WPF 通过的子类对集合中的所有访问权限进行通道 CollectionView 。和都与在 ItemsControl CollectionView 其上创建了的线程关联 ItemsControl ,这意味着将禁止在不同的线程上使用它们,并引发异常。实际上,此限制也适用于集合。

可能需要在多个线程上使用集合。例如,你希望在 "数据收集" 线程上更新集合(添加或删除项),同时在 "用户界面" 线程上显示结果,以便 UI 在数据收集过程中保持响应。在这种情况下,您需要负责确保对集合的同步("线程安全")访问。通常使用简单的锁定机制或更精细的同步机制(如信号量、重置事件等)来完成此操作。  虽然您必须将应用程序的访问权限同步到集合,但您还必须确保从 WPF (特别是从)进行的访问 CollectionView 参与相同的同步机制。为此,可调用 EnableCollectionSynchronization 方法。

若要在多个线程上使用集合(其中一个线程是拥有的 UI 线程 ItemsControl ),应用程序具有以下职责:

  1. 选择同步机制。

  2. 使用该机制将应用程序中的所有访问同步到集合。

  3. 调用 EnableCollectionSynchronization 以告知 WPF 的机制。

  4. 确保对集合所做的更改和该更改的通知(通过)具有原子性, INotifyCollectionChanged 而不能从其他线程访问。(这通常是免费的。 例如, ObservableCollection<T> 如果所有更改均受同步保护,则可保证这样。)

  5. 如果调用  DisableCollectionSynchronization ,则该调用还必须在 UI 线程上发生。

  6. 如果要在多个 UI 线程上使用同一集合,则必须 EnableCollectionSynchronization DisableCollectionSynchronization 在每个 ui 线程上分别调用(和,如果需要)。

  7. 避免死锁。它在选择使用同步时已成为应用程序的责任,但它还必须考虑 WPF 参与同步的情况,如下一段所述。

在返回中,WPF 提供以下行为:

  • CollectionView使用给定的同步机制访问集合。

  • CollectionView维护集合的 "卷影副本",以供在 UI 线程上使用。

  • CollectionChanged事件在到达时(在任何线程上)排队。

  • 挂起事件会在 UI 线程上以异步方式应用于该卷影副本。

  • CollectionView不会直接使用对应用程序可见的任何其他同步机制。 这是 WPF 有助于避免死锁的方法(请参阅上一项7)。  

最终效果是,可以更改任何线程上的集合,这些更改最终会出现在 ItemsControl UI 线程有时间进行 "更新" 的情况下。已对实现进行了优化,以限制更改流向 UI 线程的速率,以使后台线程保持对 UI 线程的饱和,并从而使对正常用户输入的响应。

EnableCollectionSynchronization(IEnumerable, Object)

通过使用简单的锁定机制,使 CollectionView 对象能够参与对多个线程上使用的集合的同步访问。

C#复制

public static void EnableCollectionSynchronization (System.Collections.IEnumerable collection, object lockObject);

参数

collection

IEnumerable

需同步访问的集合。

lockObject

Object

访问集合时要锁定的对象。

注解

WPF 应用程序可以使用 ItemsControl 或它的一个子类( ListBox 、 DataGrid 、 TreeView 、等 ListView )来显示数据的集合。WPF 通过的子类对集合中的所有访问权限进行通道 CollectionView 。和都与在 ItemsControl CollectionView 其上创建了的线程关联 ItemsControl ,这意味着将禁止在不同的线程上使用它们,并引发异常。实际上,此限制也适用于集合。

可能需要在多个线程上使用集合。例如,你希望在 "数据收集" 线程上更新集合(添加或删除项),同时在 "用户界面" 线程上显示结果,以便 UI 在数据收集过程中保持响应。在这种情况下,您负责确保对集合的同步("线程安全")访问,并确保从 WPF (特别是从)进行的访问 CollectionView 参与相同的同步机制。通过调用 EnableCollectionSynchronization(IEnumerable, Object) 方法,可以使用简单的锁定机制来实现此目的。

若要在多个线程上使用集合,其中一个线程是拥有的 UI 线程 ItemsControl ,则必须执行以下操作:

  1. 在访问集合时实例化要锁定的对象。

  2. 通过锁定对象将应用程序中的所有访问同步到集合。

  3. 调用 EnableCollectionSynchronization(IEnumerable, Object) 以告知 WPF 你使用的是简单的锁定机制。

    • 调用必须在 UI 线程上发生。

    • 在另一线程上使用集合之前,或在将集合附加到之前,必须先调用 ItemsControl ,以之后的为准。

  4. 确保对集合所做的更改和该更改的通知(通过)具有原子性, INotifyCollectionChanged 而不能从其他线程访问。(这通常是免费的。 例如, ObservableCollection<T> 如果所有更改均受同步保护,则可保证这样。)

  5. 如果调用  DisableCollectionSynchronization ,则该调用还必须在 UI 线程上发生。

  6. 如果要在多个 UI 线程上使用同一集合,则必须 EnableCollectionSynchronization DisableCollectionSynchronization 在每个 ui 线程上分别调用(和,如果需要)。

  7. 避免死锁。它在选择使用同步时已成为应用程序的责任,但它还必须考虑 WPF 参与同步的情况。(请参阅下面的详细信息。)

在返回中,WPF 提供以下行为:

  • CollectionView使用锁定机制访问集合。

  • CollectionView维护集合的 "卷影副本",以供在 UI 线程上使用。

  • CollectionChanged事件在到达时(在任何线程上)排队。

  • 挂起事件会在 UI 线程上以异步方式应用于该卷影副本。

  • CollectionView不会直接使用对应用程序可见的任何其他同步机制。 这是 WPF 有助于避免死锁的方法(请参阅上一项7)。  

最终效果是,可以更改任何线程上的集合,这些更改最终会出现在 ItemsControl UI 线程有时间进行 "更新" 的情况下。已对实现进行了优化,以限制更改流向 UI 线程的速率,以使后台线程保持对 UI 线程的饱和,并从而使对正常用户输入的响应。

适用于

.NET 5.0 和其他版本

EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback)

通过使用机制而不是简单的锁定,使 CollectionView 对象能够参与对多个线程上使用的集合的同步访问。

C#复制

public static void EnableCollectionSynchronization (System.Collections.IEnumerable collection, object context, System.Windows.Data.CollectionSynchronizationCallback synchronizationCallback);

参数

collection

IEnumerable

需同步访问的集合。

context

Object

传递给回调的对象。

synchronizationCallback

CollectionSynchronizationCallback

每当需要访问集合时,就会调用的回调。 可用于确保集合一次被一个线程访问。

注解

WPF 应用程序可以使用 ItemsControl 或它的一个子类( ListBox 、 DataGrid 、 TreeView 、等 ListView )来显示数据的集合。WPF 通过的子类对集合中的所有访问权限进行通道 CollectionView 。和都与在 ItemsControl CollectionView 其上创建了的线程关联 ItemsControl ,这意味着将禁止在不同的线程上使用它们,并引发异常。实际上,此限制也适用于集合。

可能需要在多个线程上使用集合。例如,你希望在 "数据收集" 线程上更新集合(添加或删除项),同时在 "用户界面" 线程上显示结果,以便 UI 在数据收集过程中保持响应。在这种情况下,您负责确保对集合的同步("线程安全")访问,并确保从 WPF (特别是从)进行的访问 CollectionView 参与相同的同步机制。 通过调用 EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback) 方法,可以通过使用同步机制(如信号量、重置事件等)来执行此操作。  若要在多个线程上使用集合,其中一个线程是拥有的 UI 线程 ItemsControl ,则必须执行以下操作:

  1. 选择同步机制。

  2. 使用该机制将应用程序中的所有访问同步到集合。

  3. 调用 EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback) 重载,通知 WPF 你使用的机制不是简单锁定。

    • 调用必须在 UI 线程上发生。

    • 在另一线程上使用集合之前,或在将集合附加到之前,必须先调用 ItemsControl ,以之后的为准。

  4. 确保对集合所做的更改和该更改的通知(通过)具有原子性, INotifyCollectionChanged 而不能从其他线程访问。(这通常是免费的。 例如, ObservableCollection<T> 如果所有更改均受同步保护,则可保证这样。)

  5. 如果调用  DisableCollectionSynchronization ,则该调用还必须在 UI 线程上发生。

  6. 如果要在多个 UI 线程上使用同一集合,则必须 EnableCollectionSynchronization DisableCollectionSynchronization 在每个 ui 线程上分别调用(和,如果需要)。

  7. 避免死锁。它在选择使用同步时已成为应用程序的责任,但它还必须考虑 WPF 参与同步的情况。(请参阅下面的详细信息。)

在返回中,WPF 提供以下行为:

  • CollectionView通过调用使用以下参数注册的来访问集合 CollectionSynchronizationCallback :

    • collection:感兴趣的集合。
    • context:已注册的上下文对象。
    • accessMethod:执行实际访问的委托。
    • writeAccess: true 如果委托将修改集合,则为; false 否则为。

    CollectionSynchronizationCallback应在集合上建立同步( context 根据需要使用对象和 writeAccess 值),调用 accessMethod ,然后释放同步。

  • CollectionView维护集合的 "卷影副本",以供在 UI 线程上使用。

  • CollectionChanged事件在到达时(在任何线程上)排队。

  • 挂起事件会在 UI 线程上以异步方式应用于该卷影副本。

  • CollectionView不会直接使用对应用程序可见的任何其他同步机制。 这是 WPF 有助于避免死锁的方法(请参阅上一项7)。  

最终效果是,可以更改任何线程上的集合,这些更改最终会出现在 ItemsControl UI 线程有时间进行 "更新" 的情况下。已对实现进行了优化,以限制更改流向 UI 线程的速率,以使后台线程保持对 UI 线程的饱和,并从而使对正常用户输入的响应。

context参数是传递到的任意对象 callback 。 您可以使用它来确定用于控制对的访问的同步机制 collection 。 Context可以为 null 。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值