Click here to Skip to main content
11,490,003 members (69,450 online)
Click here to Skip to main content
Add your own
alternative version

Building a 3-Tier App with Silverlight 3, .NET RIA Services, and Azure Table Storage

, 11 Jul 2009 CDDL 110.9K 1.6K 149
This article presents the techniques and caveats of building a 3-tire Azure hosted application using Silverlight 3 (presentation tier), .NET RIA services (business logic and data access), and Windows Azure Table (data storage).
Azurelight_SourceCode.zip
Azurelight
Azure
DomainServices
Linq
Properties
StorageClient
Azurelight
Azurelight
Azurelight.ccproj
Azurelight_WebRole
ServiceConfiguration.cscfg
ServiceDefinition.csdef
Azurelight_WebRole
App_Data
Azurelight.mdf
Azurelight_log.ldf
App_GlobalResources
System.Web.Silverlight.dll
ClientBin
Global.asax
Model
Properties
Service
AzurelightNav
Command
Control
Generated_Code
Model
Properties
Resources
SilverlightCairngorm
Business
Command
Control
Model
Properties
Views
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
	{
		#region Constructor

		/// <summary>
		/// Turn any type that implements IEnumerable(T) into BindableCollection
		/// </summary>
		/// <param name="listData"></param>
		public BindableCollection(IEnumerable<T> listData) : base(null) 
		{
			ListSource = listData;
		}

		/// <summary>
		/// Default parameter-less constructor. It'll create an instance of inner list, or the client can set the property ListSource at any time
		/// </summary>
		public BindableCollection() : this(new ObservableCollection<T>()) { }

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

		public BindableCollection(ObservableCollection<T> listData, Dispatcher dispatcher) : base(dispatcher)
        {
			InitListData(listData);
        }
        #endregion

		#region data binding events wire up

		private ObservableCollection<T> list = null;
		public IEnumerable<T> ListSource
		{
			get { return (null == list) ? null : list as IEnumerable<T>; }
			set
			{
				if (value == list)
					return;
				UninitListData();

				var listData = new ObservableCollection<T>();
				foreach (T ti in value)
					listData.Add(ti);
				InitListData(listData);
			}
		}

		private NotifyCollectionChangedEventHandler listBindingHandler = null;
		private PropertyChangedEventHandler propBindingHandler = null;

		private void InitListData(ObservableCollection<T> listData)
		{
			if (listData == null)
			{
				throw new ArgumentNullException("The list must not be null for BindableCollection InitListData");
			}

			this.list = listData;

			INotifyCollectionChanged collectionChanged = list as INotifyCollectionChanged;
			if (null == listBindingHandler)
				listBindingHandler = new NotifyCollectionChangedEventHandler(NotifyCollectionChanged);
			collectionChanged.CollectionChanged += listBindingHandler;

			INotifyPropertyChanged propertyChanged = list as INotifyPropertyChanged;
			if (null == propBindingHandler)
				propBindingHandler = new PropertyChangedEventHandler(NotifyPropertyChangedDelegate);
			propertyChanged.PropertyChanged += propBindingHandler;
		}

		private void UninitListData()
		{
			if (null == list)
				return;

			INotifyCollectionChanged collectionChanged = list as INotifyCollectionChanged;
			collectionChanged.CollectionChanged -= listBindingHandler;

			INotifyPropertyChanged propertyChanged = list as INotifyPropertyChanged;
			propertyChanged.PropertyChanged -= propBindingHandler;

			list = null;
		}

		#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);
		}

		protected void NotifyPropertyChangedDelegate(object sender, PropertyChangedEventArgs e)
		{
			base.NotifyPropertyChanged(e.PropertyName); //base already took care of Dispatcher
		}

		#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)

Share

About the Author

Modesty Zhang
Technical Lead
United States United States
Tech Lead of large scale consumer facing software offerings, specializing in Web and Mobile application architecting and development.

Specialties:
Web App/ iOS / Cocoa Touch / HTML5 / CSS3 / Ajax / jQuery / jQuery Mobile / jQuery UI / Node.js / Rich JavaScript Application / RESTful Web Services / Java EE 6 / Java 7 / PHP / Ruby on Rails / and Windows / .NET / RIA / Flex / Flash / Silverlight / Software Architecting / Front End Design and Development

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150520.1 | Last Updated 12 Jul 2009
Article Copyright 2009 by Modesty Zhang
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid