]> O.S.I.I.S - jp/crow.git/commitdiff
Template binding instantiation, dynamic event handler emition.
authorjpbruyere <jp.bruyere@hotmail.com>
Wed, 14 Dec 2016 00:03:55 +0000 (01:03 +0100)
committerjpbruyere <jp.bruyere@hotmail.com>
Wed, 14 Dec 2016 00:03:55 +0000 (01:03 +0100)
intermediate save.
modifié :         src/CompilerServices/CompilerServices.cs
modifié :         src/IML/Context.cs
modifié :         src/IML/Node.cs
modifié :         src/IML/NodeAddress.cs
modifié :         src/Instantiator.cs

src/CompilerServices/CompilerServices.cs
src/IML/Context.cs
src/IML/Node.cs
src/IML/NodeAddress.cs
src/Instantiator.cs

index 85e240e9f270ef745fdeb1274fdfe65f29df9073..8f587d39c37956dd96d87a1896f1031510832224 100644 (file)
@@ -16,7 +16,7 @@ namespace Crow
                        BindingFlags.NonPublic | BindingFlags.Instance);
                internal static MethodInfo stringEquals = typeof (string).GetMethod
                        ("Equals", new Type [3] { typeof (string), typeof (string), typeof (StringComparison) });
-               static MethodInfo miFindByName = typeof (GraphicObject).GetMethod ("FindByName");
+               public static MethodInfo miFindByName = typeof (GraphicObject).GetMethod ("FindByName");
 
                public static MethodInfo miIFaceLoad = typeof(Interface).GetMethod ("Load", BindingFlags.Instance | BindingFlags.Public);
                public static MethodInfo miGetITemp = typeof(Interface).GetMethod ("GetItemTemplate");
index 965d0062edf6cd5ebc10d49b07ab230d0f1adb2e..4f9ba30d3e82040323ada9b15dff42ad5fbb864f 100644 (file)
@@ -38,7 +38,6 @@ namespace Crow.IML
        {
                public XmlTextReader reader = null;
                public Type RootType = null;
-               public int CurrentIndex = 0;
 
                public DynamicMethod dm = null;
                public ILGenerator il = null;
@@ -46,7 +45,6 @@ namespace Crow.IML
                public NodeStack nodesStack = new NodeStack ();
 
                public Dictionary<string, List<NodeAddress>> Names  = new Dictionary<string, List<NodeAddress>>();
-               public Dictionary<string, Dictionary<string, MemberAddress>> PropertyBindings = new Dictionary<string, Dictionary<string, MemberAddress>> ();
 
                public Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>> Bindings =
                        new Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>>();
@@ -75,21 +73,6 @@ namespace Crow.IML
                        get { return nodesStack.Peek().CrowType; }
                }
 
-               public MethodInfo CurrentAddMethod {
-                       get {
-                               if (typeof (Group).IsAssignableFrom (CurrentNodeType))
-                                       return CompilerServices.miAddChild;
-                               if (typeof (Container).IsAssignableFrom (CurrentNodeType))
-                                       return CompilerServices.miSetChild;
-                               if (typeof (TemplatedContainer).IsAssignableFrom (CurrentNodeType))
-                                       return CurrentIndex < 0 ? CompilerServices.miLoadTmp : CompilerServices.miSetContent;
-                               if (typeof (TemplatedGroup).IsAssignableFrom (CurrentNodeType))
-                                       return CurrentIndex < 0 ? CompilerServices.miLoadTmp : CompilerServices.miAddItem;
-                               if (typeof (TemplatedControl).IsAssignableFrom (CurrentNodeType))
-                                       return CompilerServices.miLoadTmp;
-                               return null;
-                       }
-               }
                void initILGen ()
                {
                        il.DeclareLocal (typeof (GraphicObject));
index 14cffdb29f5b071b606e75ac5f53b53bfcb8e900..a9e9bb807315aca1de30d73486b4ffb94f14f0cc 100644 (file)
@@ -26,14 +26,13 @@ using System.Collections.Generic;
 namespace Crow.IML
 {
        /// <summary>
-       /// IML Node are the elements of the interface XML,
+       /// IML Node are defined with a type and the index in the parent,
        /// </summary>
        public struct Node
        {
+               /// <summary> Current node type</summary>
                public Type CrowType;
-               /// <summary>
-               /// Indexer for group child, -1 for template
-               /// </summary>
+               /// <summary> Index in parent, -1 for template</summary>
                public int Index;
 
                public Node (Type crowType, int _index = 0)
@@ -42,6 +41,20 @@ namespace Crow.IML
                        Index = _index;
                }
 
+               public MethodInfo GetAddMethod(int childIdx){
+                       if (typeof (Group).IsAssignableFrom (CrowType))
+                               return CompilerServices.miAddChild;
+                       if (typeof (Container).IsAssignableFrom (CrowType))
+                               return CompilerServices.miSetChild;
+                       if (typeof (TemplatedContainer).IsAssignableFrom (CrowType))
+                               return childIdx < 0 ? CompilerServices.miLoadTmp : CompilerServices.miSetContent;
+                       if (typeof (TemplatedGroup).IsAssignableFrom (CrowType))
+                               return childIdx < 0 ? CompilerServices.miLoadTmp : CompilerServices.miAddItem;
+                       if (typeof (TemplatedControl).IsAssignableFrom (CrowType))
+                               return CompilerServices.miLoadTmp;
+                       return null;
+               }
+
                #region Equality Compare
                public override bool Equals (object obj)
                {
index 1c907ec1cdbfb0a85b408c7354c09b2aaa68e23b..460998dadd61586f06ea506e505a77b5ec11de75 100644 (file)
@@ -31,7 +31,7 @@ namespace Crow.IML
                public NodeAddress (Node[] nodes) : base(nodes) { 
                }
 
-               public Type NodeType { get { return this[this.Count -1].CrowType; }}
+               public Type NodeType { get { return Count == 0 ? null : this[this.Count -1].CrowType; }}
 
                public override bool Equals (object obj)
                {
index b5ffbe832ae6b726091f1311313b5c4418c1d565..7804cd15bc28ba1d135f15b11c6a2cb7fc0abcae 100644 (file)
@@ -85,8 +85,11 @@ namespace Crow
 
                List<DynamicMethod> dsValueChangedDynMeths = new List<DynamicMethod>();
                List<Delegate> dataSourceChangedDelegates = new List<Delegate>();
+               List<Delegate> templateValueChangedDelegates = new List<Delegate>();
                Dictionary<string, Delegate> bindingDelegates = new Dictionary<string, Delegate>();//valuechanged del
                Dictionary<string, Delegate> bindingInitializer = new Dictionary<string, Delegate>();//initialize with actual values of binding origine
+               List<Delegate> eventDynHandlers = new List<Delegate>();
+               Delegate templateBinding;
 
                #region IML parsing
                /// <summary>
@@ -95,7 +98,9 @@ namespace Crow
                void parseIML (XmlTextReader reader) {
                        Context ctx = new Context (findRootType (reader));
 
-                       emitLoader (reader, ctx, ctx.RootType);
+                       ctx.nodesStack.Push (new Node (ctx.RootType));
+                       emitLoader (reader, ctx);
+                       ctx.nodesStack.Pop ();
 
                        emitBindingDelegates (ctx);
 
@@ -129,9 +134,8 @@ namespace Crow
                        }
                        return t;
                }
-               void emitLoader (XmlTextReader reader, Context ctx, Type newType)
+               void emitLoader (XmlTextReader reader, Context ctx)
                {
-                       ctx.nodesStack.Push(new Node (newType, ctx.CurrentIndex));
                        string tmpXml = reader.ReadOuterXml ();
 
                        if (ctx.nodesStack.Peek().HasTemplate)
@@ -140,10 +144,8 @@ namespace Crow
                        emitGOLoad (ctx, tmpXml);
 
                        emitCheckAndBindValueChanged (ctx);
-
-                       ctx.nodesStack.Pop ();
                }
-               void emitTemplateLoad (Context ctx, string tmpXml) {                    
+               void emitTemplateLoad (Context ctx, string tmpXml) {
                        //if its a template, first read template elements
                        using (XmlTextReader reader = new XmlTextReader (tmpXml, XmlNodeType.Element, null)) {
                                List<string []> itemTemplateIds = new List<string []> ();
@@ -159,8 +161,7 @@ namespace Crow
                                        if (reader.Name == "Template") {
                                                inlineTemplate = true;
                                                reader.Read ();
-                                               ctx.CurrentIndex = -1;
-                                               readChildren (reader, ctx);
+                                               readChildren (reader, ctx, -1);
                                        } else if (reader.Name == "ItemTemplate") {
                                                string dataType = "default", datas = "", path = "";
                                                while (reader.MoveToNextAttribute ()) {
@@ -251,7 +252,9 @@ namespace Crow
                                                if (mi == null)
                                                        throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNodeType.Name);
                                                if (mi.MemberType == MemberTypes.Event) {
-                                                       //CompilerServices.emitBindingCreation (ctx.il, reader.Name, reader.Value);
+                                                       if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
+                                                               emitEventHandler(ctx, mi as EventInfo,reader.Value.Substring (1, reader.Value.Length - 2));
+                                                       //else //emit handler binding
                                                        continue;
                                                }
                                                PropertyInfo pi = mi as PropertyInfo;
@@ -260,10 +263,10 @@ namespace Crow
 
                                                if (pi.Name == "Name"){
                                                        if (!ctx.Names.ContainsKey(reader.Value))
-                                                               ctx.Names[reader.Value] = new List<NodeAddress>();                                                      
+                                                               ctx.Names[reader.Value] = new List<NodeAddress>();
                                                        ctx.Names[reader.Value].Add(ctx.CurrentNodeAddress);
                                                }
-                                               
+
                                                if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
                                                        readPropertyBinding (ctx, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
                                                else
@@ -274,18 +277,18 @@ namespace Crow
                                }
                                #endregion
 
-                               if (!reader.IsEmptyElement) {
-                                       ctx.CurrentIndex = 0;
-                                       readChildren (reader, ctx);
-                               }
+                               readChildren (reader, ctx);
+
+                               ctx.nodesStack.ResetCurrentNodeIndex ();
                        }
                }
                /// <summary>
                /// Parse child node an generate corresponding msil
                /// </summary>
-               void readChildren (XmlTextReader reader, Context ctx)
+               void readChildren (XmlTextReader reader, Context ctx, int startingIdx = 0)
                {
                        bool endTagReached = false;
+                       int nodeIdx = startingIdx;
                        while (reader.Read ()) {
                                switch (reader.NodeType) {
                                case XmlNodeType.EndElement:
@@ -319,13 +322,15 @@ namespace Crow
                                        ctx.il.Emit (OpCodes.Stloc_0);//child is now loc_0
                                        CompilerServices.emitSetCurInterface (ctx.il);
 
-                                       emitLoader (reader, ctx, t);
+                                       ctx.nodesStack.Push (new Node (t, nodeIdx));
+                                       emitLoader (reader, ctx);
+                                       ctx.nodesStack.Pop ();
 
                                        ctx.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting
-                                       ctx.il.Emit (OpCodes.Callvirt, ctx.CurrentAddMethod);
+                                       ctx.il.Emit (OpCodes.Callvirt, ctx.nodesStack.Peek().GetAddMethod(nodeIdx));
                                        ctx.il.Emit (OpCodes.Stloc_0); //reset local to current go
 
-                                       ctx.CurrentIndex++;
+                                       nodeIdx++;
 
                                        break;
                                }
@@ -335,7 +340,6 @@ namespace Crow
                }
                #endregion
 
-
                void emitCheckAndBindValueChanged(Context ctx){
                        System.Reflection.Emit.Label labContinue = ctx.il.DefineLabel ();
                        string strNA = ctx.CurrentNodeAddress.ToString ();
@@ -357,7 +361,7 @@ namespace Crow
                        //attach to valuechanged handler
                        ctx.il.Emit(OpCodes.Callvirt, typeof(IValueChange).GetEvent("ValueChanged").AddMethod);
 
-                       //call initializer 
+                       //call initializer
                        ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
                        ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("bindingInitializer", BindingFlags.Instance | BindingFlags.NonPublic));
                        ctx.il.Emit (OpCodes.Ldstr, strNA);//load binding id for current node
@@ -367,11 +371,7 @@ namespace Crow
 
                        ctx.il.MarkLabel (labContinue);
                }
-               /// <summary>
-               /// Tries the find target.
-               /// </summary>
-               /// <returns>The member address in the graphic tree, null if on dataSource, </returns>
-               /// <param name="expression">Expression.</param>
+
                void readPropertyBinding (Context ctx, string sourceMember, string expression)
                {
                        MemberAddress targetMember;
@@ -382,7 +382,7 @@ namespace Crow
 
                        //if binding exp = '{}' => binding is done on datasource
                        if (string.IsNullOrEmpty (expression))
-                               return;                 
+                               return;
 
                        if (expression.StartsWith ("²")) {
                                expression = expression.Substring (1);
@@ -398,26 +398,8 @@ namespace Crow
                        }
 
                        NodeAddress currentNode = ctx.CurrentNodeAddress;
-                       int ptr = currentNode.Count - 1;
 
-                       //if exp start with '/' => Graphic tree parsing start at source
-                       if (string.IsNullOrEmpty (bindingExp [0])) {
-                               //TODO:
-                       } else if (bindingExp [0] == ".") { //search template root
-                               while (ptr > 0) {
-                                       ptr--;
-                                       if (typeof(TemplatedControl).IsAssignableFrom (currentNode [ptr].CrowType))
-                                               break;
-                               }
-                       } else if (bindingExp [0] == "..") { //search starting at current node
-                               int levelUp = bindingExp.Length - 1;
-                               if (levelUp > ptr)
-                                       throw new Exception ("Binding error: try to bind outside IML source");
-                               ptr -= levelUp;
-                       }
-                       Node[] targetNode = new Node[ptr+1];
-                       Array.Copy (currentNode.ToArray (), targetNode, ptr + 1);
-                       NodeAddress targetNA = new NodeAddress (targetNode);
+                       NodeAddress targetNA = getNodeAdressFromBindingExp (currentNode, bindingExp);
 
                        string [] bindTrg = bindingExp.Last().Split ('.');
 
@@ -468,6 +450,30 @@ namespace Crow
                        Debug.WriteLine ("Property less binding: " + Target + expression);
                        #endif
                }
+               NodeAddress getNodeAdressFromBindingExp(NodeAddress currentNode, string[] bindingExp){
+                       int ptr = currentNode.Count - 1;
+
+                       //if exp start with '/' => Graphic tree parsing start at source
+                       if (string.IsNullOrEmpty (bindingExp [0])) {
+                               //TODO:
+                       } else if (bindingExp [0] == ".") { //search template root
+                               ptr--;
+                               while (ptr >= 0) {
+                                       if (typeof(TemplatedControl).IsAssignableFrom (currentNode [ptr].CrowType))
+                                               break;
+                                       ptr--;
+                               }
+
+                       } else if (bindingExp [0] == "..") { //search starting at current node
+                               int levelUp = bindingExp.Length - 1;
+                               if (levelUp > ptr)
+                                       throw new Exception ("Binding error: try to bind outside IML source");
+                               ptr -= levelUp;
+                       }
+                       Node[] targetNode = new Node[ptr+1];
+                       Array.Copy (currentNode.ToArray (), targetNode, ptr + 1);
+                       return new NodeAddress (targetNode);
+               }
                /// <summary>
                /// create the valuechanged handler, the datasourcechanged handler and emit event handling
                /// </summary>
@@ -531,8 +537,8 @@ namespace Crow
                        #endregion
 
                        #region emit dataSourceChanged event handler
-                       //now we create the datasource changed method that will init the destination member with 
-                       //the actual value of the origin member of the datasource and then will bind the value changed 
+                       //now we create the datasource changed method that will init the destination member with
+                       //the actual value of the origin member of the datasource and then will bind the value changed
                        //dyn methode.
                        //dm is bound to the instanciator instance to have access to cached dyn meth and delegates
                        dm = new DynamicMethod ("dyn_dschanged",
@@ -569,8 +575,7 @@ namespace Crow
 
                        //store dschange delegate in instatiator instance for access while instancing graphic object
                        int delDSIndex = dataSourceChangedDelegates.Count;
-                       Delegate del = dm.CreateDelegate (CompilerServices.ehTypeDSChange, this);
-                       dataSourceChangedDelegates.Add(del);
+                       dataSourceChangedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
                        #endregion
 
                        #region Emit datasourcechanged handler binding in the loader context
@@ -578,10 +583,150 @@ namespace Crow
                        ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
                        ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("dataSourceChangedDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
                        ctx.il.Emit(OpCodes.Ldc_I4, delDSIndex);//load delegate index
-                       ctx.il.Emit(OpCodes.Callvirt, typeof(List<DynamicMethod>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+                       ctx.il.Emit(OpCodes.Callvirt, typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
                        ctx.il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetEvent("DataSourceChanged").AddMethod);//call add event
                        #endregion
                }
+               /// <summary>
+               /// Compile events expression in IML attributes, and store the result in the instanciator
+               /// Those handlers will be bound when instatiing
+               /// </summary>
+               void emitEventHandler (Context ctx, EventInfo sourceEvent, string expression)
+               {
+                       #if DEBUG_BINDING
+                       Debug.WriteLine ("\tCompile Event Source ");
+                       #endif
+
+
+                       #region Retrieve EventHandler parameter type
+                       MethodInfo evtInvoke = sourceEvent.EventHandlerType.GetMethod ("Invoke");
+                       ParameterInfo [] evtParams = evtInvoke.GetParameters ();
+                       Type handlerArgsType = evtParams [1].ParameterType;
+                       #endregion
+
+                       Type [] args = { typeof (object), handlerArgsType };
+                       DynamicMethod dm = new DynamicMethod ("dyn_eventHandler",
+                                                  typeof(void),
+                                                  args, true);
+
+
+                       #region IL generation
+                       NodeAddress currentNode = ctx.CurrentNodeAddress;
+                       string strNA = currentNode.ToString();
+
+                       ILGenerator il = dm.GetILGenerator (256);
+                       il.Emit (OpCodes.Nop);
+
+                       string [] srcLines = expression.Trim ().Split (new char [] { ';' });
+
+                       foreach (string srcLine in srcLines) {
+                               string statement = srcLine.Trim ();
+
+                               string [] operandes = statement.Split (new char [] { '=' });
+                               if (operandes.Length < 2) //not an affectation
+                               {
+                                       //maybe we could handle here handler function name
+                                       continue;
+                               }
+
+                               string rop = operandes [operandes.Length - 1].Trim ();
+
+                               #region LEFT OPERANDES
+                               string [] lopParts = operandes [0].Trim ().Split ('/');
+                               Type lopType = currentNode.NodeType;
+                               MemberInfo lopMI = null;
+
+                               il.Emit (OpCodes.Ldarg_0);  //load sender ref onto the stack
+
+                               if (lopParts.Length > 1) {
+                                       NodeAddress lopNA = getNodeAdressFromBindingExp (currentNode, lopParts);
+                                       emitGetInstance (il, currentNode, lopNA);
+                                       lopType = lopNA.NodeType;
+                               }
+
+                               string [] bindTrg = lopParts.Last().Split ('.');
+
+                               if (bindTrg.Length == 1)
+                                       lopMI = lopType.GetMember (bindTrg [0]).FirstOrDefault();
+                               else if (bindTrg.Length == 2) {
+                                       //named target
+                                       //TODO:
+                                       il.Emit(OpCodes.Ldstr, bindTrg[0]);
+                                       il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetMethod("FindByName"));
+                                       lopMI = lopType.GetMember (bindTrg [1]).FirstOrDefault();
+                               } else
+                                       throw new Exception ("Syntax error in binding, expected 'go dot member'");
+
+
+                               if (lopMI == null)
+                                       throw new Exception (string.Format ("IML BINDING: Member not found"));
+
+                               OpCode lopSetOpCode;
+                               dynamic lopSetMI;
+                               Type lopT = null;
+                               switch (lopMI.MemberType) {
+                               case MemberTypes.Property:
+                                       lopSetOpCode = OpCodes.Callvirt;
+                                       PropertyInfo lopPi = lopMI as PropertyInfo;
+                                       lopT = lopPi.PropertyType;
+                                       lopSetMI = lopPi.GetSetMethod ();
+                                       break;
+                               case MemberTypes.Field:
+                                       lopSetOpCode = OpCodes.Stfld;
+                                       FieldInfo dstFi = lopMI as FieldInfo;
+                                       lopT = dstFi.FieldType;
+                                       lopSetMI = dstFi;
+                                       break;
+                               default:
+                                       throw new Exception (string.Format ("GOML:member type not handle"));
+                               }
+                               #endregion
+
+                               #region RIGHT OPERANDES
+                               if (rop.StartsWith ("\'")) {
+                                       if (!rop.EndsWith ("\'"))
+                                               throw new Exception (string.Format
+                                                       ("GOML:malformed string constant in handler: {0}", rop));
+                                       string strcst = rop.Substring (1, rop.Length - 2);
+
+                                       il.Emit (OpCodes.Ldstr, strcst);
+
+                               } else {
+                                       if (lopT.IsEnum)
+                                               throw new NotImplementedException ();
+
+                                       MethodInfo lopParseMi = lopT.GetMethod ("Parse");
+                                       if (lopParseMi == null)
+                                               throw new Exception (string.Format
+                                                       ("GOML:no parse method found in: {0}", lopT.Name));
+                                       il.Emit (OpCodes.Ldstr, rop);
+                                       il.Emit (OpCodes.Callvirt, lopParseMi);
+                                       il.Emit (OpCodes.Unbox_Any, lopT);
+                               }
+
+                               #endregion
+
+                               //emit left operand assignment
+                               il.Emit (lopSetOpCode, lopSetMI);
+                       }
+
+                       il.Emit (OpCodes.Ret);
+
+                       #endregion
+
+                       //store event handler dynamic method in instanciator
+                       int dmIdx = eventDynHandlers.Count;
+                       eventDynHandlers.Add (dm.CreateDelegate (sourceEvent.EventHandlerType));
+
+                       #region Emit event handler binding in the loader context
+                       ctx.il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
+                       ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+                       ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("eventDynHandlers", BindingFlags.Instance | BindingFlags.NonPublic));
+                       ctx.il.Emit(OpCodes.Ldc_I4, dmIdx);//load delegate index
+                       ctx.il.Emit(OpCodes.Callvirt, typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+                       ctx.il.Emit(OpCodes.Callvirt, sourceEvent.AddMethod);//call add event
+                       #endregion
+               }
 
                /// <summary>
                /// Create and store in the instanciator the ValueChanged delegates
@@ -589,129 +734,240 @@ namespace Crow
                /// need to be bound to destination instance as in the ancient system.
                /// </summary>
                void emitBindingDelegates(Context ctx){
-                       foreach (KeyValuePair<NodeAddress,Dictionary<string, List<MemberAddress>>> bindings in ctx.Bindings ) { 
+                       foreach (KeyValuePair<NodeAddress,Dictionary<string, List<MemberAddress>>> bindings in ctx.Bindings ) {
+                               if (bindings.Key.Count == 0)
+                                       emitTemplateBindingDelegate (ctx, bindings.Value);
+                               else
+                                       emitBindingDelegate (bindings.Key, bindings.Value);
+                       }
+               }
+               void emitTemplateBindingDelegate(Context ctx, Dictionary<string, List<MemberAddress>> bindings){
+                       //value changed dyn method
+                       DynamicMethod dm = new DynamicMethod ("dyn_tmpValueChanged",
+                               typeof (void), CompilerServices.argsValueChange, true);
+
+                       ILGenerator il = dm.GetILGenerator (256);
+
+                       System.Reflection.Emit.Label endMethod = il.DefineLabel ();
 
-                               Type origineNodeType = bindings.Key.NodeType;
+                       il.DeclareLocal (typeof(object));
 
-                               //init method, current instance passed as arg
-                               DynamicMethod dmInit = new DynamicMethod ("dyn_initBinding",
-                                       typeof (void), new Type[] {typeof(object)}, true);
-                               ILGenerator ilInit = dmInit.GetILGenerator (256);
-                               ilInit.Emit (OpCodes.Nop);
+                       il.Emit (OpCodes.Nop);
 
-                               //value changed dyn method
-                               DynamicMethod dm = new DynamicMethod ("dyn_valueChanged",
-                                       typeof (void), CompilerServices.argsValueChange, true);
+                       int i = 0;
+                       foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings ) {
 
-                               ILGenerator il = dm.GetILGenerator (256);
+                               System.Reflection.Emit.Label nextTest = il.DefineLabel ();
 
-                               System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+                               #region member name test
+                               //load source member name
+                               il.Emit (OpCodes.Ldarg_1);
+                               il.Emit (OpCodes.Ldfld, typeof(ValueChangeEventArgs).GetField ("MemberName"));
 
-                               il.DeclareLocal (typeof(object));
+                               il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
+                               il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+                               il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+                               il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
+                               #endregion
 
-                               il.Emit (OpCodes.Nop);
-                               //il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+                               #region destination member affectations
 
-                               int i = 0;
-                               foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings.Value ) {
-                                       Type origineType = origineNodeType.GetProperty (bindingCase.Key).PropertyType;
+                               foreach (MemberAddress ma in bindingCase.Value) {
+                                       //first we have to load destination instance onto the stack, it is access
+                                       //with graphic tree functions deducted from nodes topology
+                                       il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
 
-                                       System.Reflection.Emit.Label nextTest = il.DefineLabel ();
+                                       emitGetChild (il, typeof(TemplatedControl), -1);
+                                       emitGetInstance (il, ma.Address);
 
-                                       #region member name test
-                                       //load source member name
+                                       //load new value
                                        il.Emit (OpCodes.Ldarg_1);
-                                       il.Emit (OpCodes.Ldfld, typeof(ValueChangeEventArgs).GetField ("MemberName"));
+                                       il.Emit (OpCodes.Ldfld, typeof (ValueChangeEventArgs).GetField ("NewValue"));
+
+                                       Type dstType = ma.Property.PropertyType;
+                                       if (dstType == typeof (string))
+                                               il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+                                       else if (dstType.IsValueType) {
+                                               il.Emit (OpCodes.Unbox_Any, dstType);//TODO:double check this
+                                       }else
+                                               il.Emit (OpCodes.Castclass, dstType);
+
+                                       il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
+                               }
+                               #endregion
+                               il.Emit (OpCodes.Br, endMethod);
+                               il.MarkLabel (nextTest);
+
+                               i++;
+                       }
+                       //il.Emit (OpCodes.Pop);
+                       il.MarkLabel (endMethod);
+                       il.Emit (OpCodes.Ret);
+
+                       //store template bindings in instanciator
+                       templateBinding = dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>));
 
-                                       il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
-                                       il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
-                                       il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
-                                       il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
-                                       #endregion
+                       #region emit ParentChanged handler
+                       dm = new DynamicMethod ("dyn_parentChanged",
+                               typeof (void),
+                               CompilerServices.argsDSChange, true);
 
-                                       #region destination member affectations
-                                       foreach (MemberAddress ma in bindingCase.Value) {
-                                               //for initialisation dynmeth, load current instance
-                                               ilInit.Emit(OpCodes.Ldarg_0);
-                                               //first we have to load destination instance onto the stack, it is access
-                                               //with graphic tree functions deducted from nodes topology
-                                               il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+                       il = dm.GetILGenerator (256);
 
-                                               NodeAddress origine = bindings.Key;
-                                               NodeAddress destination = ma.Address;
+                       il.Emit (OpCodes.Nop);
 
-                                               emitGetInstance(il,origine,destination);
-                                               emitGetInstance(ilInit,origine,destination);
+                       //load new parent onto the stack for handler addition
+                       il.Emit (OpCodes.Ldarg_2);
+                       il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+
+                       //Load cached delegate
+                       il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+                       il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("templateBinding", BindingFlags.Instance | BindingFlags.NonPublic));
+
+                       //add template bindings dynValueChanged delegate to new parent event
+                       il.Emit(OpCodes.Callvirt, typeof(IValueChange).GetEvent("ValueChanged").AddMethod);//call add event
+                       il.Emit (OpCodes.Ret);
 
-                                               //init dynmeth: load actual value
-                                               ilInit.Emit (OpCodes.Ldarg_0);
-                                               ilInit.Emit (OpCodes.Callvirt, origineNodeType.GetProperty (bindingCase.Key).GetGetMethod());
+                       //store dschange delegate in instatiator instance for access while instancing graphic object
+                       int delDSIndex = dataSourceChangedDelegates.Count;
+                       dataSourceChangedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
+                       #endregion
 
-                                               //load new value
-                                               il.Emit (OpCodes.Ldarg_1);
-                                               il.Emit (OpCodes.Ldfld, typeof (ValueChangeEventArgs).GetField ("NewValue"));
+                       #region Emit datasourcechanged handler binding in the loader context
+                       ctx.il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
+                       ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+                       ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("dataSourceChangedDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
+                       ctx.il.Emit(OpCodes.Ldc_I4, delDSIndex);//load delegate index
+                       ctx.il.Emit(OpCodes.Callvirt, typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+                       ctx.il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetEvent("ParentChanged").AddMethod);//call add event
+                       #endregion
 
-                                               emitConvert(ilInit,origineType,ma.Property.PropertyType);
-                                               emitConvert(il,origineType, ma.Property.PropertyType);
+               }
+               void emitBindingDelegate(NodeAddress origine, Dictionary<string, List<MemberAddress>> bindings){
+                       Type origineNodeType = origine.NodeType;
 
-                                               //set value
-                                               ilInit.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
-                                               il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
+                       //init method, current instance passed as arg
+                       DynamicMethod dmInit = new DynamicMethod ("dyn_initBinding",
+                               typeof (void), new Type[] {typeof(object)}, true);
+                       ILGenerator ilInit = dmInit.GetILGenerator (256);
+                       ilInit.Emit (OpCodes.Nop);
 
-                                               il.Emit (OpCodes.Br, endMethod);
-                                               il.MarkLabel (nextTest);
-                                       }
-                                       #endregion
+                       //value changed dyn method
+                       DynamicMethod dm = new DynamicMethod ("dyn_valueChanged",
+                               typeof (void), CompilerServices.argsValueChange, true);
+
+                       ILGenerator il = dm.GetILGenerator (256);
+
+                       System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+
+                       il.DeclareLocal (typeof(object));
+
+                       il.Emit (OpCodes.Nop);
+
+                       int i = 0;
+                       foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings ) {
+
+                               System.Reflection.Emit.Label nextTest = il.DefineLabel ();
+
+                               #region member name test
+                               //load source member name
+                               il.Emit (OpCodes.Ldarg_1);
+                               il.Emit (OpCodes.Ldfld, typeof(ValueChangeEventArgs).GetField ("MemberName"));
+
+                               il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
+                               il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+                               il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+                               il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
+                               #endregion
+
+                               #region destination member affectations
+                               Type origineType = origineNodeType.GetProperty (bindingCase.Key).PropertyType;
+                               foreach (MemberAddress ma in bindingCase.Value) {
+                                       //for initialisation dynmeth, load current instance
+                                       ilInit.Emit(OpCodes.Ldarg_0);
+                                       //first we have to load destination instance onto the stack, it is access
+                                       //with graphic tree functions deducted from nodes topology
+                                       il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+
+                                       NodeAddress destination = ma.Address;
+
+                                       emitGetInstance (il, origine, destination);
+                                       emitGetInstance (ilInit, origine, destination);
+
+                                       //init dynmeth: load actual value
+                                       ilInit.Emit (OpCodes.Ldarg_0);
+                                       ilInit.Emit (OpCodes.Callvirt, origineNodeType.GetProperty (bindingCase.Key).GetGetMethod());
+
+                                       //load new value
+                                       il.Emit (OpCodes.Ldarg_1);
+                                       il.Emit (OpCodes.Ldfld, typeof (ValueChangeEventArgs).GetField ("NewValue"));
+
+                                       if (origineType != ma.Property.PropertyType)//no unboxing required
+                                               emitConvert (ilInit, origineType, ma.Property.PropertyType);
+                                       emitConvert (il, origineType, ma.Property.PropertyType);//unboxing required
+
+                                       //set value
+                                       ilInit.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
+                                       il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
 
-                                       i++;
                                }
-                               //il.Emit (OpCodes.Pop);
-                               il.MarkLabel (endMethod);
-                               ilInit.Emit (OpCodes.Ret);
-                               il.Emit (OpCodes.Ret);
+                               #endregion
+                               il.Emit (OpCodes.Br, endMethod);
+                               il.MarkLabel (nextTest);
 
-                               bindingDelegates [bindings.Key.ToString()] = dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>));
-                               bindingInitializer [bindings.Key.ToString()] = dmInit.CreateDelegate (typeof(Action<object>));
+                               i++;
                        }
+                       //il.Emit (OpCodes.Pop);
+                       il.MarkLabel (endMethod);
+                       ilInit.Emit (OpCodes.Ret);
+                       il.Emit (OpCodes.Ret);
+
+                       bindingDelegates [origine.ToString()] = dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>));
+                       bindingInitializer [origine.ToString()] = dmInit.CreateDelegate (typeof(Action<object>));
                }
                void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){
-                       if (orig.Count < dest.Count){
-                               for (int i = orig.Count-1; i < dest.Count-1; i++){
-                                       if (typeof (Group).IsAssignableFrom (dest[i].CrowType)) {
-                                               il.Emit (OpCodes.Ldfld, typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic));
-                                               il.Emit(OpCodes.Ldc_I4, dest[i+1].Index);
-                                               il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
-                                               continue;
-                                       }
-                                       if (typeof(Container).IsAssignableFrom (dest[i].CrowType) || dest[i+1].Index < 0) {
-                                               il.Emit (OpCodes.Ldfld, typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic));
-                                               continue;
-                                       }
-                                       if (typeof(TemplatedContainer).IsAssignableFrom (dest[i].CrowType)) {
-                                               il.Emit (OpCodes.Callvirt, typeof(TemplatedContainer).GetProperty ("Content").GetGetMethod ());
-                                               continue;
-                                       }
-                                       if (typeof(TemplatedGroup).IsAssignableFrom (dest[i].CrowType)) {
-                                               il.Emit (OpCodes.Callvirt, typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ());
-                                               il.Emit(OpCodes.Ldc_I4, dest[i+1].Index);
-                                               il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
-                                               continue;
-                                       }
-                               }
+                       if (orig.Count < dest.Count) {
+                               for (int i = orig.Count - 1; i < dest.Count - 1; i++)
+                                       emitGetChild (il, dest [i].CrowType, dest [i + 1].Index);
+                       } else {
+                               for (int j = dest.Count; j < orig.Count; j++)
+                                       il.Emit (OpCodes.Callvirt, typeof(ILayoutable).GetProperty ("Parent").GetGetMethod ());
+                       }
+               }
+               void emitGetInstance (ILGenerator il, NodeAddress dest){
+                       for (int i = 0; i < dest.Count - 1; i++)
+                               emitGetChild (il, dest [i].CrowType, dest [i + 1].Index);
+               }
+               void emitGetChild(ILGenerator il, Type parentType, int index){
+                       if (typeof (Group).IsAssignableFrom (parentType)) {
+                               il.Emit (OpCodes.Ldfld, typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic));
+                               il.Emit(OpCodes.Ldc_I4, index);
+                               il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+                               return;
+                       }
+                       if (typeof(Container).IsAssignableFrom (parentType) || index < 0) {
+                               il.Emit (OpCodes.Ldfld, typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic));
+                               return;
+                       }
+                       if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) {
+                               il.Emit (OpCodes.Callvirt, typeof(TemplatedContainer).GetProperty ("Content").GetGetMethod ());
+                               return;
+                       }
+                       if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) {
+                               il.Emit (OpCodes.Callvirt, typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ());
+                               il.Emit(OpCodes.Ldc_I4, index);
+                               il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
                                return;
                        }
-
-                       for (int j = dest.Count; j < orig.Count; j++)
-                               il.Emit(OpCodes.Callvirt, typeof(ILayoutable).GetProperty("Parent").GetGetMethod());
                }
-               void emitConvert(ILGenerator il, Type origType, Type destType){                 
+               void emitConvert(ILGenerator il, Type origType, Type destType){
                        if (destType == typeof (string))
                                il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
                        else if (origType.IsValueType) {
                                if (destType != origType)
                                        il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType));
                                else
-                                       il.Emit (OpCodes.Unbox_Any, destType);
+                                       il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this
                        }else
                                il.Emit (OpCodes.Castclass, destType);
                }
@@ -723,7 +979,7 @@ namespace Crow
                        else if (sourceValueType != sourceValueType) {
                                il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (sourceValueType));
                        } else
-                               il.Emit (OpCodes.Unbox_Any, sourceValueType);                   
+                               il.Emit (OpCodes.Unbox_Any, sourceValueType);
                }
                //public string GetImlSourcesCode(){
                //      try {