
Initially
ThreadSafeBindingList class was created to protect collection in
multi-threading mode. However, when Dapfor's developers worked with actual applications,
they faced a serious performance issue with standard binding list working with
objects implementing INotifyPropertyChanged interface. They have discovered
reasons for low performance of BindingList with such objects and modified
ThreadSafeBindingList to significantly improve application performance while
receiving all advantages of the existing container.
Now let's learn
a little bit of history.
BindingList is
an implementation of IBindingList interface that notifies subscribers of
changes in collection. Usual subscribers are grids, lists and other graphical
controls that work with data collections. Such controls get notifications via
IBindingList.ListChanged event. This event is fired when data is
added to or
removed from the collection and upon major changes of the collection. For this
reason, ListChangedEventArgs specifies event that occurred at the collection
and the grid rebuilds its internal data presentation structure basing on this
information. There can be the following ListChangedType: ItemAdded,
ItemChanged, ItemDeleted, ItemMoved, PropertyDescriptorAdded,
PropertyDescriptorChanged, PropertyDescriptorDeleted, Reset. There are simple
types - adding/removing and complete rebuilding of data. However, ItemChanged
reason is very interesting. In this case instead of internal changes of the
collection (adding, removing, etc) the binding list reports changes of data
objects. For this purpose the binding list subscribes to each object
implementing INotifyPropertyChanged interface by adding a handler to
INotifyPropertyChanged.PropertyChanged event. By getting a notification from
such object, the binding list doesn't manipulate its internal data structure
but transforms the received notification into its own IBindingList.ListChanged
event with ItemChanged value and PropertyDescriptor corresponding to the field
of notifying
object.
The following
code can be used to get PropertyDescriptor from PropertyChangedEventArgs:
object
dataObject = ...;
string
propertyName = ""someProperty"";
PropertyDescriptor
property = TypeDescriptor.GetProperties(dataObject)[propertyName];
Performance here
is not very high, but it is not critical as there is a more serious issue.
BindingList contains internal cache that theoretically should improve
performance. This cache compares objects that fired INotifyPropertyChanged
notifications. When subsequent notifications are received from the same object,
this cache works perfectly. However, when they are fired by different objects,
the binding list tries to calculate a new index of object in the collection
that has fired the notification. For this purpose the binding list calls
List.IndexOf(object) triggering linear enumeration of all collection elements
to find the required element's index. This means that upon every notification from
objects implementing INotifyPropertyChanged, the binding list enumerates all
objects in the collection. This problem is well demonstrated with the following
code:
From theory to
practice
It is doubtful
that binding list's subscription to INotifyPropertyChanged is useful as it
doesn't process these notifications but only transforms them to
IBindingList.ListChanged format. It doesn't make any internal manipulations
with its own data.
ThreadSafeBindingList
container is only a wrapper for BindingList and fully replicates its
functionality. When Dapfor's developers discovered the cause for low
performance, they blocked BindingList subscription to INotifyPropertyChanged
events solving two problems at once. The first problem was incorrect
organization of internal cache, and the second problem was getting
notifications from objects with non-existing properties. Still,
ThreadSafeBindingList doesn't block firing notifications upon adding/removing
items just asthe standard container.
Architecture of
the .Net Grid enables it to subscribe to events of objects implementing
INotifyPropertyChanged interface without regard to the adding method. When the
grid receives notifications from these objects, it performs thread
synchronization, data update, sorting, regrouping, filtering and highlighting.
Therefore, blocking BindingList subscription to INotifyPropertyChanged
interface doesn't impact application functionality and significantly improves
their performance.
Thread safety
BindingList is
not a thread-safe container. As said above, the main purpose of creating
ThreadSafeBindingList was to protect the binding list from competitive access
by multiple application threads.
ThreadSafeBindingList
is just a wrapper that contains the BindingList and locks its internal method.
ThreadSafeBindingList implementation prevents occupation of synchronizing
object at the time when notification is fired. It is especially important to
avoid potential deadlock problems when two synchronizing objects are taken by
the opposite threads.
To summarize the
above, Dapfor recommends using ThreadSafeBindingList instead of standard
BindingList. This ensures thread protection for the application and
significantly improves application performance by optimizing usage of the
standard container.

0 Response to "Know How To Use Thread safe Bindinglist"
Post a Comment