Click here to Skip to main content
15,892,768 members
Articles / Programming Languages / Visual Basic

GUI Observer - Using the Observer pattern to handle data updates to complex linked controls

Rate me:
Please Sign up or sign in to vote.
4.09/5 (8 votes)
31 May 200613 min read 68.1K   404   51  
Use the Observer pattern to encapsulate control update code (adding items to lists etc.) in seperate classes outside of the form, and handle it when the code is called.
using System;
using System.Collections.Specialized;
using System.Collections;
using System.Windows.Forms;
using System.Drawing;

namespace Rockprint.Patterns.Custom.Observer
{
	/// <summary>
	/// Classic Pattern IObserver interface
	/// </summary>
	public interface IObserver
	{
		/// <summary>
		/// The Update() method will be called when a ISubject "notifies" it via <seealso cref="ISubject"/>
		/// </summary>
		void Update(Object newData);
	}


	/// <summary>
	/// Classic Pattern ISubject interface
	/// </summary>
	public interface ISubject
	{
		/// <summary>
		/// Attaches the specified observer to the list of observers to be notified.
		/// </summary>
		/// <param name="observer"></param>
		void Attach(IObserver observer);
		/// <summary>
		/// Detaches the specified observer to the list of observers to be notified.
		/// </summary>
		/// <param name="observer"></param>
		void Detach(IObserver observer);
		/// <summary>
		/// Notifies all "attached" observers
		/// </summary>
		void Notify(Object newData);
	}

	/// <summary>
	/// Concrete implementation of ISubject
	/// </summary>
	public class SubjectBase : ISubject
	{
		#region ISubject Members
		ArrayList _observers = new ArrayList();
		public void Attach(IObserver observer)
		{
			// SubjectBase.Attach implementation
			_observers.Add(observer);
		}

		public void Detach(IObserver observer)
		{
			// SubjectBase.Detach implementation
			_observers.Remove(observer);
		}

		public void Notify(Object newData)
		{
			// SubjectBase.Notify implementation
			
			foreach(IObserver o in _observers)
				o.Update(newData);
		}

		#endregion
		protected object _subject;
		public object Subject
		{
			get
			{ return _subject; }
			set
			{
				_subject = value;
				Notify(value);
			}

		}
	}


	// Some base datatype subjects to derive from
	public class StringSubject : SubjectBase
	{
		public StringSubject(string value)
		{
			base.Subject = value;
		}

		//protected new string _subject;
		public new string Subject
		{
			get
			{ return (string) base.Subject; }
			set
			{
				base._subject = value;
				base.Notify(value);
			}

		}
	}
	public class LongSubject : SubjectBase
	{
		public LongSubject(long value)
		{
			base.Subject = value;
		}

		//protected new string _subject;
		public new long Subject
		{
			get
			{ return (long) base.Subject; }
			set
			{
				base._subject = value;
				base.Notify(value);
			}

		}
	}
	public class IntSubject : SubjectBase
	{
		public IntSubject(int value)
		{
			base.Subject = value;
		}

		//protected new string _subject;
		public new int Subject
		{
			get
			{ return (int) base.Subject; }
			set
			{
				base._subject = value;
				base.Notify(value);
			}

		}
	}
	public class BoolSubject : SubjectBase
	{
		public BoolSubject(bool value)
		{
			base.Subject = value;
		}

		//protected new string _subject;
		public new bool Subject
		{
			get
			{ return (bool) base.Subject; }
			set
			{
				base._subject = value;
				base.Notify(value);
			}

		}
	}
	public class DateSubject : SubjectBase
	{
		public DateSubject(DateTime value)
		{
			base.Subject = value;
		}

		//protected new string _subject;
		public new DateTime Subject
		{
			get
			{ return (DateTime) base.Subject; }
			set
			{
				base._subject = value;
				base.Notify(value);
			}

		}
	}
	/// <summary>
	/// Specialised Observer class designed to observe when the GUI needs updating.
	/// GUIObserver's contain references objects that implement the <see cref="IGUIUpdate">IGUIUpdate</see> interface.
	/// When a GUIObserver is notififed, it's IObserver.Update method calls IGUIUpdate.Init if required (will only be called once)
	/// followed by IGUIUpdate.Reset and IGUIUpdate.Fill
	/// </summary>
	
	/// <summary>
	/// Defines the three main operations required in displaying a visual control
	/// Init - Initialises an empty control to a default state with no data (i.e. setting column headings but no rows)
	/// Reset - Resets the control back to initalised state (may simple call Init again, or remove the items from a ListView
	/// Fill - Populates the control, it is up to individual implementations to deal with gathering the data to populate the control.
	/// 
	/// Objects implementing this interface need to maintain/create there own references/pointers to the controls required to update
	/// and the data required to update them.
	/// 
	/// See the example "updater" below.
	/// </summary>
	public interface IGUIUpdate
	{
		/// <summary>
		/// This is the subject that control represents. If a control is cleared or changed in other programmatic ways the
		/// subject may also be set.
		/// </summary>
		SubjectBase ControlSubject
		{
			get ; set;
		}

		/// <summary>
		/// Buffer that will contain the a value sent via the Observer pattern through the notify method.
		/// The value type and content will be specific to the deriving class.
		/// </summary>
		Object NewData
		{
			get; set;
		}

		void Init();
		void Reset();
		void Fill();
	}

	public abstract class GUIUpdateBase : IGUIUpdate
	{
		private SubjectBase _controlSubject;

		public SubjectBase ControlSubject
		{
			get { return _controlSubject;}
			set { _controlSubject = value;}
		}

		private Object _newData;

		public Object NewData
		{
			get { return _newData;}
			set { _newData = value;}
		}

		public abstract void Init();
		public abstract void Reset();
		public abstract void Fill();
			
	}
	public sealed class GUIObserver : IObserver
	{
		private IGUIUpdate _update;
		private bool _initialised;
		#region IObserver Members

		public void Update(Object newData)
		{
			Console.WriteLine("{0}.Update called for {1}", base.GetType().ToString(), _update.GetType().ToString());
			initUpdater();
			_update.NewData= newData;
			_update.Reset();
			_update.Fill();
		}

	
		#endregion

		public GUIObserver(IGUIUpdate update) : this(update, false)
		{
		}

		public GUIObserver(IGUIUpdate update, bool initialiseNow)
		{
			_update = update;
			if(initialiseNow)
				initUpdater();
		}

		private void initUpdater()
		{
			if(!_initialised)
			{
				_update.Init();
				_initialised = true;
			}
		}

	}

}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions