Click here to Skip to main content
15,893,487 members
Articles / Web Development / HTML

Property Events

Rate me:
Please Sign up or sign in to vote.
4.76/5 (11 votes)
3 May 2005CPOL12 min read 61.5K   365   36  
Declarative programming of Property Events
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;

namespace MyXaml.MxHelpers
{
	public class EventTargetNullException : ApplicationException
	{
		public EventTargetNullException(string msg) : base(msg) {}
	}

	public class EventBindingException : ApplicationException
	{
		public EventBindingException(string msg) : base(msg) {}
	}

	public class SetValueException : ApplicationException
	{
		public SetValueException(string msg) : base(msg) {}
	}

	public class NoPropertyException : ApplicationException
	{
		public NoPropertyException(string msg) : base(msg) {}
	}

	public interface ISetter
	{
		void Update(ref bool stop);
	}

	public interface ICondition
	{
		bool IsMet(object obj, bool stateValidated);
	}

	public class CheckState : ISetter
	{
		protected OnEvent onEvent;

		public OnEvent OnEvent
		{
			get {return onEvent;}
			set {onEvent=value;}
		}

		public void Update(ref bool stop)
		{
			onEvent.EventHandler(onEvent.Object, EventArgs.Empty);
		}
	}

	public class Stop : ISetter
	{
		public void Update(ref bool stop)
		{
			stop=true;
		}
	}

	public class Set : ISetter
	{
		protected string val;
		protected object obj;
		protected string property;

		public string Value
		{
			get {return val;}
			set {val=value;}
		}

		public object Object
		{
			get {return obj;}
			set {obj=value;}
		}

		public string Property
		{
			get {return property;}
			set {property=value;}
		}

		public void Update(ref bool stop)
		{
			PropertyInfo pi=obj.GetType().GetProperty(property);
			if (pi==null)
			{
				throw(new NoPropertyException("Property "+property+" not found."));
			}

			TypeConverter tc=TypeDescriptor.GetConverter(pi.PropertyType);
			object v=val;
			if (tc.CanConvertFrom(typeof(string)))
			{
				v=tc.ConvertFromInvariantString(val);
			}

			try
			{
				pi.SetValue(obj, v, null);
			}
			catch(Exception e)
			{
				throw(new SetValueException(e.Message));
			}
		}
	}

	public class OnCondition : ICondition
	{
		protected object obj;
		protected string val;
		protected string property;

		public object Object
		{
			get {return obj;}
			set {obj=value;}
		}

		public string Value
		{
			get {return val;}
			set {val=value;}
		}

		public string Property
		{
			get {return property;}
			set {property=value;}
		}

		public bool IsMet(object obj, bool stateValidated)
		{
			// Use object if specified, otherwise, use the event object.
			if (this.obj != null)
			{
				obj=this.obj;
			}

			PropertyInfo pi=obj.GetType().GetProperty(property);
			if (pi==null)
			{
				throw(new NoPropertyException("Property "+property+" not found."));
			}
			TypeConverter tc=TypeDescriptor.GetConverter(pi.PropertyType);
			object v=val;
			if (tc.CanConvertFrom(typeof(string)))
			{
				v=tc.ConvertFromInvariantString(val);
			}
			bool ret=v.Equals(pi.GetValue(obj, null));
			return ret;
		}
	}

	public class OnOtherCondition : ICondition
	{
		public bool IsMet(object obj, bool stateValidated)
		{
			return !stateValidated;
		}
	}

	public class OnAnyCondition : ICondition
	{
		public bool IsMet(object obj, bool stateValidated)
		{
			return true;
		}
	}

	public class OnEvent : ISupportInitialize
	{
		protected object obj;
		protected string ev;
		protected ArrayList states;

		public object Object
		{
			get {return obj;}
			set {obj=value;}
		}

		public string Event
		{
			get {return ev;}
			set {ev=value;}
		}

		public ArrayList States
		{
			get {return states;}
		}

		public OnEvent()
		{
			states=new ArrayList();
		}

		public void BeginInit()
		{
		}

		public void EndInit()
		{
			if (obj==null)
			{
				throw(new EventTargetNullException("Event target is null."));
			}

			EventInfo ei=obj.GetType().GetEvent(ev, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
			if (ei==null)
			{
				throw(new EventBindingException("Can't find event "+ev));
			}


			Delegate dlgt=null;
			try
			{
				dlgt=Delegate.CreateDelegate(ei.EventHandlerType, this, "EventHandler");
			}
			catch {}

			if (dlgt==null)
			{
				throw(new EventBindingException("Can't create delegate generic for event "+ev));
			}

			ei.AddEventHandler(obj, dlgt);
		}

		public void EventHandler(object sender, EventArgs ea)
		{
			Trace.WriteLine("Event");
			bool stateValidated=false;
			bool stop=false;
			foreach(State state in states)
			{
				stateValidated|=state.Test(sender, stateValidated, ref stop);
				if (stop)
				{
					break;
				}
			}
		}
	}

	public class State
	{
		protected string description;
		protected ArrayList conditions;
		protected ArrayList setters;

		public string Description
		{
			get {return description;}
			set {description=value;}
		}

		public ArrayList Conditions
		{
			get {return conditions;}
		}

		public ArrayList Setters
		{
			get {return setters;}
		}

		public State()
		{
			conditions=new ArrayList();
			setters=new ArrayList();
		}

		public bool Test(object obj, bool stateValidated, ref bool stop)
		{
			bool qualified=true;
			foreach(ICondition cond in conditions)
			{
				bool ret=cond.IsMet(obj, stateValidated);
				qualified&=ret;
				if (!ret)
				{
					break;
				}
			}
			if (qualified)
			{
				foreach(ISetter setter in setters)
				{
					setter.Update(ref stop);
					if (stop)
					{
						break;
					}
				}
			}
			return qualified;
		}
	}

	public class MxObjectStateManagement
	{
		protected ArrayList events;

		public ArrayList Events
		{
			get {return events;}
		}

		public MxObjectStateManagement()
		{
			events=new ArrayList();
		}
	}
}

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 Code Project Open License (CPOL)


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions