Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Romeo and Juliet

, 3 Dec 2011
Making relationships first class citizens.
XTreePropertyGrid.zip
XTreePropertyGrid
Clifton.Tools.Strings
bin
Debug
Clifton.Tools.Strings.dll
Release
Xml Documentation
obj
Debug
Refactor
TempPE
Xml Documentation
TempPE
UnitTests
Clifton.Windows.Forms
bin
Debug
Clifton.Tools.Strings.dll
Clifton.Windows.Forms.dll
Release
obj
Debug
Refactor
TempPE
Properties
Resources
tv_minus.bmp
tv_plus.bmp
XmlTree
.svn
all-wcprops
entries
prop-base
props
text-base
INode.cs.svn-base
IXtreeNode.cs.svn-base
Node.cs.svn-base
NodeDef.cs.svn-base
NodeInstance.cs.svn-base
NodeMenuItem.cs.svn-base
PlaceholderInstance.cs.svn-base
Popup.cs.svn-base
RootNode.cs.svn-base
XtreeNodeController.cs.svn-base
tmp
prop-base
props
text-base
Myxaml 2.0
MyXaml.Core
bin
Debug
Clifton.Tools.Strings.dll
MyXaml.Core.dll
UnitTest.dll
Release
Xml Documentation
doc
MyXamlCoreUnitTests
obj
Debug
Refactor
TempPE
Release
Xml Documentation
TempPE
MyXaml.WinForms
bin
Debug
Clifton.Tools.Strings.dll
MyXaml.Core.dll
MyXaml.WinForms.dll
UnitTest.dll
Release
Xml Documentation
obj
Debug
Refactor
TempPE
Xml Documentation
TempPE
ROPLib
bin
Debug
ROPLib.dll
XTreeInterfaces.dll
Release
obj
Debug
Refactor
TempPE
Properties
ROPLib.csproj.user
UnitTest
bin
Debug
UnitTest.dll
Release
Xml Documentation
obj
Debug
Refactor
TempPE
Xml Documentation
TempPE
UnitTest.csproj.user
XTreeIIDemo
bin
Debug
Clifton.Tools.Strings.dll
Clifton.Windows.Forms.dll
MyXaml.Core.dll
MyXaml.WinForms.dll
ROPLib.dll
schemaEditor.myxaml
UnitTest.dll
XTreeIIDemo.exe
XTreeIIDemo.vshost.exe
XTreeIIDemo.vshost.exe.manifest
XTreeInterfaces.dll
Properties
XTreeInterfaces
bin
Debug
XTreeInterfaces.dll
Release
obj
Debug
TempPE
Properties
/*
 * Copyright (c) 2004, 2005 MyXaml
 * All Rights Reserved
 * 
 * Licensed under the terms of the GNU General Public License
 * http://www.gnu.org/licenses/licenses.html#GPL
*/

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Xml;

using Clifton.Tools.Strings;

using MyXaml.Core.Exceptions;

namespace MyXaml.Core
{
	/// <summary>
	/// Assists with property and event assignment for values that contain a reference.
	/// Also supports binding on objects that implement IExtenderProvider.
	/// </summary>
	public class MxBinding
	{
		private object obj;
		private string propertyName;
		private string refVal;
		private XmlNode node;
		private bool success;

		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="obj">The target instance.</param>
		/// <param name="propertyName">The property name to assign.</param>
		/// <param name="refVal">The reference, as a string.</param>
		/// <param name="node">The xml node while element is the object instance.</param>
		public MxBinding(object obj, string propertyName, string refVal, XmlNode node)
		{
			this.obj=obj;
			this.propertyName=propertyName;
			this.refVal=refVal;
			this.node=node;
			success=false;
		}

		/// <summary>
		/// Attempt to bind the referenced value to the property of the object.
		/// </summary>
		/// <param name="parser">The calling parser instance.</param>
		/// <returns>True if assignment is successful.</returns>
		public bool Bind(Parser parser)
		{
			bool ret=success;													// Assume last success state.
			if (!success)														// If we haven't succeeded yet...
			{
				string refName=StringHelpers.LeftOf(refVal, ';').Trim();		// Get the reference name.
				string parms=StringHelpers.RightOf(refVal, ';').Trim();			// Get any optional parameters that get assigned to the reference before the reference is assigned to the object.

				EventInfo ei=obj.GetType().GetEvent(propertyName);				// Get the EventInfo for this property.
				if (ei == null)													// If it's not an event...
				{
					ret=parser.ContainsReference(StringHelpers.LeftOf(refName, '.'));		// If the parser contains the reference...
					if (ret)
					{
						object propertyValueObj=parser.ResolveValue(refName);	// Get the referenced instance.
						while (parms != String.Empty)							// For each parameter...
						{
							// parameters further qualify the object being returned
							string pName=StringHelpers.LeftOf(					// Get the parameter name.
								parms, '=').Trim();
							string vName=StringHelpers.LeftOf(					// Get the value to assign to the parameter.
								StringHelpers.RightOf(parms, '='), ';').Trim();				

							if (propertyValueObj is IExtenderProvider)			// If the referenced instance implements IExtenderProvider...
							{
								if (!((IExtenderProvider)propertyValueObj).CanExtend(obj))	// But it doesn't extend the current object...
								{
									throw(new ExtenderProviderException("Cannot extend object."));	// Throw an exception.
								}

								Type t=propertyValueObj.GetType();				// Get the type for the referenced instance.
								MethodInfo mi=t.GetMethod(pName,				// Get the setter method as specified by the parameter name.
									BindingFlags.Public | 
									BindingFlags.NonPublic | 
									BindingFlags.Instance | 
									BindingFlags.Static);
								if (mi != null)									// If the method exists...
								{
									object vNameConverted=null;
									try
									{
										ParameterInfo[] pis=mi.GetParameters();	// Get the parameters that the method takes.
										if (pis.Length != 2)					// Make sure it accepts two, and only two, parameters
										{
											throw(new ExtenderProviderException("Extender provider setter does not take two parameters."));
										}
										TypeConverter tc=TypeDescriptor.GetConverter(			// Get the type converter for the parameter.
											pis[1].ParameterType);
										vNameConverted=tc.ConvertFromInvariantString(vName);	// Convert our value to the parameter type.
									}
									catch
									{
										throw(new ExtenderProviderException("Extender provider value conversion failed."));
									}
									try
									{
										mi.Invoke(propertyValueObj,				// Call the setter method.
											new object[] {obj, vNameConverted});
										ret=true;
										return ret;								// Only one parameter is allowed.
									}
									catch
									{
										throw(new ExtenderProviderException("Extender provider setter failed."));
									}
								}
								else
								{
									throw(new ExtenderProviderException("Unsupported method format for setter."));
								}
							}
							else												// Not an IExtenderProvider class
							{
								parser.SetPropertyValue(						// Set the property value of the referenced instance.
									propertyValueObj, 
									pName, 
									"", 
									vName, 
									node, 
									true);
							}
							parms=StringHelpers.RightOf(parms, ';');			// Move to the next parameter.
						}

						ret=parser.SetPropertyValue(							// Set the property value of the object to the referenced instance.
							obj, 
							propertyName, 
							"", 
							propertyValueObj, 
							node, 
							true);

						if (ret)
						{
							success=true;
						}
					}
				}
				else															// The property is an event handler.
				{
					if (refVal.IndexOf('.') == -1)								// The referenced value must be of the format <instance>.<method>
					{
						throw(new ReferencedEventMissingHandlerException("Missing handler in event reference."));
					}

					string methodName=StringHelpers.RightOf(refVal, '.').Trim();// Get the method name.
					string refObjName=StringHelpers.LeftOf(refName, '.');
					if (parser.ContainsReference(refObjName))
					{
						object propertyValueObj=parser.ResolveValue(refObjName);	// Get the referenced instance.
						Delegate dlgt=parser.FindHandlerForTarget(					// Get the delegate for the specified method.
							propertyValueObj, ei, methodName);

						if (dlgt==null)												// It must exist.
						{
							throw(new EventWireUpException("Couldn't identify an appropriate delegate."));
						}

						try
						{
							ei.AddEventHandler(obj, dlgt);							// Assign the event to the delegate.
							success=true;
							ret=true;
						}
						catch
						{
							throw(new EventWireUpException("Couldn't identify an appropriate delegate."));
						}
					}
				}
			}
			return ret;
		}
	}
}

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)

Share

About the Author

Marc Clifton

United States United States
Marc is the creator of two open source projets, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website, www.marcclifton.com, where you will find many of his articles and his blog.
 
Marc lives in Philmont, NY.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 3 Dec 2011
Article Copyright 2011 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid