Bewerken

Share via


BindingOperations.EnableCollectionSynchronization Method

Definition

Enables a CollectionView object to participate in synchronized access to a collection that is used on multiple threads.

Overloads

EnableCollectionSynchronization(IEnumerable, Object)

Enables a CollectionView object to participate in synchronized access to a collection used on multiple threads by using a simple locking mechanism.

EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback)

Enables a CollectionView object to participate in synchronized access to a collection used on multiple threads by using a mechanism other than a simple lock.

Remarks

A WPF application can display a collection of data using an ItemsControl or one of its subclasses (ListBox, DataGrid, TreeView, ListView, etc.). WPF channels all its access to the collection through a subclass of CollectionView. Both the ItemsControl and the CollectionView have affinity to the thread on which the ItemsControl was created, meaning that using them on a different thread is forbidden and throws an exception. In effect, this restriction applies to the collection as well.

You may want to use the collection on multiple threads.   For example, you want to update the collection (add or remove items) on a "data-gathering" thread, while displaying the results on a "user interface" thread, so that the UI remains responsive while data-gathering is happening. In such a situation, you are responsible for ensuring synchronized ("thread-safe") access to the collection.   This is typically done using either a simple lock mechanism or a more elaborate synchronization mechanism such as semaphores, reset events, etc.

While you must synchronize your application's access to the collection, you must also guarantee that access from WPF (specifically from CollectionView) participates in the same synchronization mechanism.  You do this by calling the EnableCollectionSynchronization method.

To use a collection on multiple threads, one of which is the UI thread that owns the ItemsControl, an application has the following responsibilities:

  1. Choose a synchronization mechanism.

  2. Synchronize all access from the application to the collection using that mechanism.

  3. Call EnableCollectionSynchronization to inform WPF of the mechanism.

  4. Ensure that a change to the collection and the notification of that change (through INotifyCollectionChanged) are atomic; no access from other threads can intervene.  (This is usually free. For instance, ObservableCollection<T> guarantees this, provided that all changes are protected by synchronization.)

  5. If you call DisableCollectionSynchronization, that call must also occur on the UI thread.

  6. If you want to use the same collection on multiple UI threads, you must call EnableCollectionSynchronization (and DisableCollectionSynchronization, if needed) separately on each UI thread.

  7. Avoid deadlock.  This is already the application's responsibility once it chooses to use synchronization, but it must also take into account WPF's participation in the synchronization, as discussed in the following paragraph.

In return, WPF provides the following behavior:

  • The CollectionView accesses the collection using the given synchronization mechanism.

  • The CollectionView maintains a "shadow copy" of the collection for use on the UI thread.

  • CollectionChanged events are queued up as they arrive (on any thread).

  • Pending events are applied to the shadow copy asynchronously on the UI thread when it has the opportunity to do so.

  • The CollectionView won't directly use any other synchronization mechanism visible to the application. This is WPF's way of helping to avoid deadlock (see the previous item 7).  

The net effect is that you can change the collection on any thread, and those changes eventually appear in the ItemsControl when the UI thread has time to "catch up".  The implementation has been tuned to throttle the rate that changes flow into the UI thread to keep background threads from saturating the UI thread and starving the response to normal user input.

EnableCollectionSynchronization(IEnumerable, Object)

Enables a CollectionView object to participate in synchronized access to a collection used on multiple threads by using a simple locking mechanism.

public:
 static void EnableCollectionSynchronization(System::Collections::IEnumerable ^ collection, System::Object ^ lockObject);
public static void EnableCollectionSynchronization (System.Collections.IEnumerable collection, object lockObject);
static member EnableCollectionSynchronization : System.Collections.IEnumerable * obj -> unit
Public Shared Sub EnableCollectionSynchronization (collection As IEnumerable, lockObject As Object)

Parameters

collection
IEnumerable

The collection that needs synchronized access.

lockObject
Object

The object to lock when accessing the collection.

Remarks

A WPF application can display a collection of data using an ItemsControl or one of its subclasses (ListBox, DataGrid, TreeView, ListView, etc.). WPF channels all its access to the collection through a subclass of CollectionView. Both the ItemsControl and the CollectionView have affinity to the thread on which the ItemsControl was created, meaning that using them on a different thread is forbidden and throws an exception. In effect, this restriction applies to the collection as well.

You may want to use the collection on multiple threads.   For example, you want to update the collection (add or remove items) on a "data-gathering" thread, while displaying the results on a "user interface" thread, so that the UI remains responsive while data-gathering is happening. In such a situation, you are responsible for ensuring synchronized ("thread-safe") access to the collection and for guaranteeing that access from WPF (specifically from CollectionView) participates in the same synchronization mechanism. By calling the EnableCollectionSynchronization(IEnumerable, Object) method, you can do this by using a simple lock mechanism.

To use a collection on multiple threads, one of which is the UI thread that owns the ItemsControl, you must do the following:

  1. Instantiate an object to lock when accessing the collection.

  2. Synchronize all access from the application to the collection by locking that object.

  3. Call EnableCollectionSynchronization(IEnumerable, Object) to inform WPF that you are using a simple lock mechanism.

    • The call must occur on the UI thread.

    • The call must occur before using the collection on a different thread or before attaching the collection to the ItemsControl, whichever is later.

  4. Ensure that a change to the collection and the notification of that change (through INotifyCollectionChanged) are atomic; no access from other threads can intervene.  (This is usually free. For instance, ObservableCollection<T> guarantees this, provided that all changes are protected by synchronization.)

  5. If you call DisableCollectionSynchronization, that call must also occur on the UI thread.

  6. If you want to use the same collection on multiple UI threads, you must call EnableCollectionSynchronization (and DisableCollectionSynchronization, if needed) separately on each UI thread.

  7. Avoid deadlock.  This is already the application's responsibility once it chooses to use synchronization, but it must also take into account WPF's participation in the synchronization. (See more, below.)

In return, WPF provides the following behavior:

  • The CollectionView accesses the collection using the locking mechanism.

  • The CollectionView maintains a "shadow copy" of the collection for use on the UI thread.

  • CollectionChanged events are queued up as they arrive (on any thread).

  • Pending events are applied to the shadow copy asynchronously on the UI thread when it has the opportunity to do so.

  • The CollectionView will not directly use any other synchronization mechanism visible to the application. This is WPF's way of helping to avoid deadlock (see the previous item 7).  

The net effect is that you can change the collection on any thread, and those changes eventually appear in the ItemsControl when the UI thread has time to "catch up".  The implementation has been tuned to throttle the rate that changes flow into the UI thread to keep background threads from saturating the UI thread and starving the response to normal user input.

Applies to

EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback)

Enables a CollectionView object to participate in synchronized access to a collection used on multiple threads by using a mechanism other than a simple lock.

public:
 static void EnableCollectionSynchronization(System::Collections::IEnumerable ^ collection, System::Object ^ context, System::Windows::Data::CollectionSynchronizationCallback ^ synchronizationCallback);
public static void EnableCollectionSynchronization (System.Collections.IEnumerable collection, object context, System.Windows.Data.CollectionSynchronizationCallback synchronizationCallback);
static member EnableCollectionSynchronization : System.Collections.IEnumerable * obj * System.Windows.Data.CollectionSynchronizationCallback -> unit
Public Shared Sub EnableCollectionSynchronization (collection As IEnumerable, context As Object, synchronizationCallback As CollectionSynchronizationCallback)

Parameters

collection
IEnumerable

The collection that needs synchronized access.

context
Object

An object that is passed to the callback.

synchronizationCallback
CollectionSynchronizationCallback

The callback that is invoked whenever access to the collection is required. You can use it to ensure that the collection is accessed by one thread at a time.

Remarks

A WPF application can display a collection of data using an ItemsControl or one of its subclasses (ListBox, DataGrid, TreeView, ListView, etc.). WPF channels all its access to the collection through a subclass of CollectionView. Both the ItemsControl and the CollectionView have affinity to the thread on which the ItemsControl was created, meaning that using them on a different thread is forbidden and throws an exception. In effect, this restriction applies to the collection as well.

You may want to use the collection on multiple threads.   For example, you want to update the collection (add or remove items) on a "data-gathering" thread, while displaying the results on a "user interface" thread, so that the UI remains responsive while data-gathering is happening. In such a situation, you are responsible for ensuring synchronized ("thread-safe") access to the collection and for guaranteeing that access from WPF (specifically from CollectionView) participates in the same synchronization mechanism. By calling the EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback) method, you can do this by using a synchronization mechanism such as a semaphores, a reset event, etc.

To use a collection on multiple threads, one of which is the UI thread that owns the ItemsControl, you must do the following:

  1. Choose a synchronization mechanism.

  2. Synchronize all access from the application to the collection using that mechanism.

  3. Call the EnableCollectionSynchronization(IEnumerable, Object, CollectionSynchronizationCallback) overload to inform WPF that you are using a mechanism other than simple locking.

    • The call must occur on the UI thread.

    • The call must occur before using the collection on a different thread or before attaching the collection to the ItemsControl, whichever is later.

  4. Ensure that a change to the collection and the notification of that change (through INotifyCollectionChanged) are atomic; no access from other threads can intervene.  (This is usually free. For instance, ObservableCollection<T> guarantees this, provided that all changes are protected by synchronization.)

  5. If you call DisableCollectionSynchronization, that call must also occur on the UI thread.

  6. If you want to use the same collection on multiple UI threads, you must call EnableCollectionSynchronization (and DisableCollectionSynchronization, if needed) separately on each UI thread.

  7. Avoid deadlock.  This is already the application's responsibility once it chooses to use synchronization, but it must also take into account WPF's participation in the synchronization. (See more, below.)

In return, WPF provides the following behavior:

  • The CollectionView accesses the collection by calling the registered CollectionSynchronizationCallback with the following arguments:

    • collection: the collection of interest.
    • context: the registered context object.
    • accessMethod: a delegate that performs the actual access.
    • writeAccess: true if the delegate will modify the collection; false otherwise.

    Your CollectionSynchronizationCallback should establish synchronization on the collection (using the context object and the writeAccess value, as appropriate), call the accessMethod, then release synchronization.

  • The CollectionView maintains a "shadow copy" of the collection for use on the UI thread.

  • CollectionChanged events are queued up as they arrive (on any thread).

  • Pending events are applied to the shadow copy asynchronously on the UI thread when it has the opportunity to do so.

  • The CollectionView will not directly use any other synchronization mechanism visible to the application. This is WPF's way of helping to avoid deadlock (see the previous item 7).  

The net effect is that you can change the collection on any thread, and those changes eventually appear in the ItemsControl when the UI thread has time to "catch up".  The implementation has been tuned to throttle the rate that changes flow into the UI thread to keep background threads from saturating the UI thread and starving the response to normal user input.

The context parameter is an arbitrary object that is passed to the callback. You can use it to determine the synchronization mechanism used to control access to collection. Context can be null.

Applies to