From 6bdcdb11ea37e57d9d527f47c7dab535c800bb69 Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Fri, 16 Dec 2016 18:27:22 +0100 Subject: [PATCH] prop less bindings in normal GTobj bindings, generic binding expression splitting function (splitBindingExp) --- src/Instantiator.cs | 183 +++++++++++++++++++++++++------------------- 1 file changed, 104 insertions(+), 79 deletions(-) diff --git a/src/Instantiator.cs b/src/Instantiator.cs index 74c0da53..bfb63b81 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -400,46 +400,87 @@ namespace Crow ctx.il.MarkLabel (labContinue); } - void readPropertyBinding (Context ctx, string sourceMember, string expression) - { - MemberAddress targetMember; - NodeAddress target; - - string memberName = null; - bool twoWay = false; - - //if binding exp = '{}' => binding is done on datasource - if (string.IsNullOrEmpty (expression)) - return; + /// + /// Splits the binding expression + /// + /// true, if it's a two ways binding, false otherwise. + /// current node address + /// Binding expression + /// node address, null if on dataSource, count=0 if template binding outside current graphic tree + /// Member name. + /// Named node. + bool splitBindingExp(NodeAddress currentNode, string expression, out NodeAddress na, out string memberName, out string namedNode){ + namedNode = ""; + if (string.IsNullOrEmpty (expression)) { + na = null; + memberName = ""; + } else { + string[] bindingExp = expression.Split ('/'); - if (expression.StartsWith ("²")) { - expression = expression.Substring (1); - twoWay = true; - } + if (bindingExp.Length == 1) + na = null; + else + na = getNodeAdressFromBindingExp (currentNode, bindingExp); - string[] bindingExp = expression.Split ('/'); + string [] bindTrg = bindingExp.Last().Split ('.'); - if (bindingExp.Length == 1) { - //datasource binding - processDataSourceBinding (ctx, sourceMember, bindingExp [0]); - return; + if (bindTrg.Length == 1) + memberName = bindTrg [0]; + else if (bindTrg.Length == 2) { + //named target + namedNode = bindTrg[0]; + memberName = bindTrg [1]; + } else + throw new Exception ("Syntax error in binding, expected 'go dot member'"); } - NodeAddress currentNode = ctx.CurrentNodeAddress; - NodeAddress targetNA = getNodeAdressFromBindingExp (currentNode, bindingExp); + return expression.StartsWith ("²"); + } - string [] bindTrg = bindingExp.Last().Split ('.'); + void readPropertyBinding (Context ctx, string sourceMember, string expression) + { + string memberName, namedNode; + NodeAddress currentNode = ctx.CurrentNodeAddress, targetNA; - if (bindTrg.Length == 1) - memberName = bindTrg [0]; - else if (bindTrg.Length == 2) { - //named target - //TODO: + bool twoWay = splitBindingExp (currentNode, expression, out targetNA, out memberName, out namedNode); - memberName = bindTrg [1]; + if (targetNA == null) {//bind on data source + processDataSourceBinding (ctx, sourceMember, memberName); return; - } else - throw new Exception ("Syntax error in binding, expected 'go dot member'"); + } + +// //if binding exp = '{}' => binding is done on datasource +// if (string.IsNullOrEmpty (expression)) +// return; +// +// if (expression.StartsWith ("²")) { +// expression = expression.Substring (1); +// twoWay = true; +// } +// +// string[] bindingExp = expression.Split ('/'); +// +// if (bindingExp.Length == 1) { +// //datasource binding +// processDataSourceBinding (ctx, sourceMember, bindingExp [0]); +// return; +// } +// +// NodeAddress currentNode = ctx.CurrentNodeAddress; +// NodeAddress targetNA = getNodeAdressFromBindingExp (currentNode, bindingExp); +// +// string [] bindTrg = bindingExp.Last().Split ('.'); +// +// if (bindTrg.Length == 1) +// memberName = bindTrg [0]; +// else if (bindTrg.Length == 2) { +// //named target +// //TODO: +// +// memberName = bindTrg [1]; +// return; +// } else +// throw new Exception ("Syntax error in binding, expected 'go dot member'"); Dictionary> nodeBindings = null; if (ctx.Bindings.ContainsKey (targetNA)) @@ -452,30 +493,6 @@ namespace Crow if (!nodeBindings.ContainsKey (memberName)) nodeBindings [memberName] = new List (); nodeBindings [memberName].Add (new MemberAddress (currentNode, sourceMember)); - - // -// if (tmpTarget == null) { -// #if DEBUG_BINDING -// Debug.WriteLine ("\tBinding Target not found => " + this.ToString()); -// #endif -// return false; -// } -// -// Target = new MemberReference (tmpTarget); -// } -// -// if (Target.TryFindMember (memberName)) { -// if (TwoWayBinding) { -// // IBindable source = Target.Instance as IBindable; -// // if (source == null) -// // throw new Exception (Source.Instance + " does not implement IBindable for 2 way bindings"); -// // source.Bindings.Add (new Binding (Target, Source)); -// } -// } - #if DEBUG_BINDING - else - Debug.WriteLine ("Property less binding: " + Target + expression); - #endif } /// /// Gets the node adress from binding expression splitted with '/' starting at a given node @@ -870,17 +887,8 @@ namespace Crow ilPC.Emit (OpCodes.Ldloc_1);//push mi for value fetching ilPC.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.Public)); - Type dstType = ma.Property.PropertyType; - if (dstType == typeof (string)){ - il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); - ilPC.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); - }else if (dstType.IsValueType) { - il.Emit (OpCodes.Unbox_Any, dstType); - ilPC.Emit (OpCodes.Unbox_Any, dstType); - }else{ - il.Emit (OpCodes.Castclass, dstType); - ilPC.Emit (OpCodes.Castclass, dstType); - } + emitConvert (il, ma.Property.PropertyType); + emitConvert (ilPC, ma.Property.PropertyType); il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod()); ilPC.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod()); @@ -958,10 +966,12 @@ namespace Crow #endregion #region destination member affectations - Type origineType = origineNodeType.GetProperty (bindingCase.Key).PropertyType; + PropertyInfo piOrig = origineNodeType.GetProperty (bindingCase.Key); + Type origineType = null; + if (piOrig != null) + origineType = piOrig.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 @@ -969,23 +979,30 @@ namespace Crow 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()); + if (origineType != null){//prop less binding, no init requiered + //for initialisation dynmeth, load current instance + ilInit.Emit(OpCodes.Ldarg_0); + 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 + if (origineType == null)//property less binding + emitConvert (il, ma.Property.PropertyType); + else { + 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()); + ilInit.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set init value + } + il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set value on value changes } #endregion @@ -1048,6 +1065,14 @@ namespace Crow }else il.Emit (OpCodes.Castclass, destType); } + void emitConvert(ILGenerator il, Type dstType){ + if (dstType == typeof (string)) + il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); + else if (dstType.IsValueType) + il.Emit (OpCodes.Unbox_Any, dstType); + else + il.Emit (OpCodes.Castclass, dstType); + } void emitConvertWorking(ILGenerator il, Type sourceValueType){ if (sourceValueType == typeof (string)) { il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); -- 2.47.3