Click here to Skip to main content
15,897,226 members
Articles / Programming Languages / C#

Thread-safe Silverlight Cairngorm

Rate me:
Please Sign up or sign in to vote.
4.75/5 (9 votes)
20 Oct 2008CDDL6 min read 49.3K   320   21  
Some code changes and improvements that make the Silverlight Cairngorm thread-safe
using System;
using System.Windows;
using System.ComponentModel;
using System.Windows.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;

namespace SilverlightCairngorm
{
	/// <summary>
	/// modestyZ@hotmail.com: 2008.10
	/// Wrapper class that makes ObservableCollection thread-safe
	/// Any ObservableCollection that serves as DataContext for data binding in multi-threaded application should be wrapped by this type
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class BindableCollection<T> : BindableBase, INotifyCollectionChanged,
		IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
	{
		private ObservableCollection<T> list;

		#region Constructor

		public BindableCollection(ObservableCollection<T> list) : this(list, null) { }

		public BindableCollection(ObservableCollection<T> list, Dispatcher dispatcher) : base(dispatcher)
        {
            if (list == null)
            {
				throw new ArgumentNullException("The list must not be null for BindableCollection constructor");
            }

            this.list = list;

            INotifyCollectionChanged collectionChanged = list as INotifyCollectionChanged;
            collectionChanged.CollectionChanged += delegate(Object sender, NotifyCollectionChangedEventArgs e)
            {
				NotifyCollectionChanged(this, e);
            };

            INotifyPropertyChanged propertyChanged = list as INotifyPropertyChanged;
            propertyChanged.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
				NotifyPropertyChanged(e.PropertyName);
            };
        }
        #endregion


		#region INotifyCollectionChanged Members

		public event NotifyCollectionChangedEventHandler CollectionChanged = delegate { };
		protected void NotifyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			//the dispatcher initialization could be deferred till the first PropertyChanged event raised
			CheckDispatcher();

			//check if we are on the Dispatcher thread if not switch
			if (currentDispatcher.CheckAccess())
				CollectionChanged(this, e);
			else
				currentDispatcher.BeginInvoke(new NotifyCollectionChangedEventHandler(CollectionChanged), this, e);
		}

		#endregion

		#region ICollection<T> Members

		public void Add(T item)
		{
			list.Add(item);
		}

		public void Clear()
		{
			list.Clear();
		}

		public bool Contains(T item)
		{
			return list.Contains(item);
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			list.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return list.Count; }
		}

		public bool IsReadOnly
		{
			get { return (list as ICollection<T>).IsReadOnly; }
		}

		public bool Remove(T item)
		{
			return list.Remove(item);
		}

		#endregion

		#region IEnumerable<T> Members

		public IEnumerator<T> GetEnumerator()
		{
			return (list as IEnumerable<T>).GetEnumerator();
		}

		#endregion

		#region IList<T> Members

		public int IndexOf(T item)
		{
			return list.IndexOf(item);
		}

		public void Insert(int index, T item)
		{
			list.Insert(index, item);
		}

		public void RemoveAt(int index)
		{
			list.RemoveAt(index);
		}

		public T this[int index]
		{
			get
			{
				return list[index];
			}
			set
			{
				list[index] = value;
			}
		}
		#endregion

		#region ICollection Members

		void ICollection.CopyTo(Array array, int index)
		{
			((ICollection)list).CopyTo(array, index);
		}

		int ICollection.Count
		{
			get { return ((ICollection)list).Count; }
		}

		bool ICollection.IsSynchronized
		{
			get { return ((ICollection)list).IsSynchronized; }
		}

		object ICollection.SyncRoot
		{
			get { return ((ICollection)list).SyncRoot; }
		}

		#endregion

		#region IList Members

		int IList.Add(object value)
		{
			return ((IList)list).Add(value);
		}

		void IList.Clear()
		{
			((IList)list).Clear();
		}

		bool IList.Contains(object value)
		{
			return ((IList)list).Contains(value);
		}

		int IList.IndexOf(object value)
		{
			return ((IList)list).IndexOf(value);
		}

		void IList.Insert(int index, object value)
		{
			((IList)list).Insert(index, value);
		}

		bool IList.IsFixedSize
		{
			get { return ((IList)list).IsFixedSize; }
		}

		bool IList.IsReadOnly
		{
			get { return ((IList)list).IsReadOnly; }
		}

		void IList.Remove(object value)
		{
			((IList)list).Remove(value);
		}

		void IList.RemoveAt(int index)
		{
			((IList)list).RemoveAt(index);
		}

		object IList.this[int index]
		{
			get
			{
				return ((IList)list)[index];
			}
			set
			{
				((IList)list)[index] = value;
			}
		}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			return (list as IEnumerable).GetEnumerator();
		}

		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Technical Lead
United States United States
https://github.com/modesty

https://www.linkedin.com/in/modesty-zhang-9a43771

https://twitter.com/modestyqz

Comments and Discussions