From 9ecf0d3e8a339d3ea897942a19c7799362169efd Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Sat, 24 Dec 2016 00:05:37 +0100 Subject: [PATCH] enable two way binding, reverser binding for datasource --- src/IML/Context.cs | 4 +- src/Instantiator.cs | 90 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/IML/Context.cs b/src/IML/Context.cs index de5f480c..e08eea1f 100644 --- a/src/IML/Context.cs +++ b/src/IML/Context.cs @@ -92,8 +92,8 @@ namespace Crow.IML return; } StorePropertyBinding (bindDef.TargetNA, bindDef.TargetMember, bindDef.SourceNA, bindDef.SourceMember); -// if (bindDef.TwoWay) -// StorePropertyBinding (bindDef.SourceNA, bindDef.SourceMember, bindDef.TargetNA, bindDef.TargetMember); + if (bindDef.TwoWay) + StorePropertyBinding (bindDef.SourceNA, bindDef.SourceMember, bindDef.TargetNA, bindDef.TargetMember); } public void StoreCurrentName(string name){ if (!Names.ContainsKey(name)) diff --git a/src/Instantiator.cs b/src/Instantiator.cs index c681ff0a..5c50db18 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -360,7 +360,7 @@ namespace Crow BindingDefinition bindingDef = splitBindingExp (sourceNA, sourceMember, expression); if (bindingDef.IsDataSourceBinding)//bind on data source - emitDataSourceBindings (ctx, sourceMember, bindingDef.TargetMember); + emitDataSourceBindings (ctx, bindingDef); else ctx.StorePropertyBinding (bindingDef); } @@ -666,9 +666,8 @@ namespace Crow Type origineNodeType = origine.NodeType; //value changed dyn method - DynamicMethod dm = new DynamicMethod ("dyn_valueChanged", + DynamicMethod dm = new DynamicMethod ("dyn_valueChanged" + NewId, typeof (void), CompilerServices.argsValueChange, true); - ILGenerator il = dm.GetILGenerator (256); System.Reflection.Emit.Label endMethod = il.DefineLabel (); @@ -751,15 +750,15 @@ namespace Crow /// /// create the valuechanged handler, the datasourcechanged handler and emit event handling /// - void emitDataSourceBindings(Context ctx, string sourceMember, string dataSourceMember){ + void emitDataSourceBindings(Context ctx, BindingDefinition bindingDef){ DynamicMethod dm = null; ILGenerator il = null; int dmVC = 0; - PropertyInfo piOrigine = ctx.CurrentNodeType.GetProperty(sourceMember); + PropertyInfo piSource = ctx.CurrentNodeType.GetProperty(bindingDef.SourceMember); //if no dataSource member name is provided, valuechange is not handle and datasource change //will be used as origine value string delName = "dyn_DSvalueChanged" + NewId; - if (!string.IsNullOrEmpty(dataSourceMember)){ + if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ #region create valuechanged method dm = new DynamicMethod (delName, typeof (void), @@ -778,7 +777,7 @@ namespace Crow il.Emit (OpCodes.Ldfld, CompilerServices.fiMbName); //test if it's the expected one - il.Emit (OpCodes.Ldstr, dataSourceMember); + il.Emit (OpCodes.Ldstr, bindingDef.TargetMember); il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals); il.Emit (OpCodes.Brfalse, endMethod); @@ -793,9 +792,9 @@ namespace Crow //memberless binding, if targetMember exists, it will be used to determine target //value type for conversion - CompilerServices.emitConvert (il, piOrigine.PropertyType); + CompilerServices.emitConvert (il, piSource.PropertyType); - il.Emit (OpCodes.Callvirt, piOrigine.GetSetMethod ()); + il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ()); il.MarkLabel (endMethod); il.Emit (OpCodes.Ret); @@ -827,17 +826,17 @@ namespace Crow emitRemoveOldDataSourceHandler(il, "ValueChanged", delName); - if (!string.IsNullOrEmpty(dataSourceMember)){ + if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ il.Emit (OpCodes.Ldarg_2);//load datasource change arg il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); il.Emit (OpCodes.Brfalse, cancel);//new ds is null } #region fetch initial Value - if (!string.IsNullOrEmpty(dataSourceMember)){ + if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ il.Emit (OpCodes.Ldarg_2);//load new datasource il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); - il.Emit (OpCodes.Ldstr, dataSourceMember);//load member name + il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//load member name il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("getMemberInfoWithReflexion", BindingFlags.Static | BindingFlags.Public)); il.Emit (OpCodes.Stloc_1);//save memberInfo il.Emit (OpCodes.Ldloc_1);//push mi for test if null @@ -847,15 +846,15 @@ namespace Crow il.Emit (OpCodes.Ldarg_1);//load source of dataSourceChanged which is the dest instance il.Emit (OpCodes.Ldarg_2);//load new datasource il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); - if (!string.IsNullOrEmpty(dataSourceMember)){ + if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ il.Emit (OpCodes.Ldloc_1);//push mi for value fetching il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.Public)); } - CompilerServices.emitConvert (il, piOrigine.PropertyType); - il.Emit (OpCodes.Callvirt, piOrigine.GetSetMethod ()); + CompilerServices.emitConvert (il, piSource.PropertyType); + il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ()); #endregion - if (!string.IsNullOrEmpty(dataSourceMember)){ + if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ il.MarkLabel(cancelInit); il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack @@ -865,6 +864,15 @@ namespace Crow il.Emit(OpCodes.Ldc_I4, dmVC);//load index of dynmathod il.Emit (OpCodes.Call, typeof(Instantiator).GetMethod("dataSourceChangedEmitHelper", BindingFlags.Instance | BindingFlags.NonPublic)); + if (bindingDef.TwoWay){ + il.Emit (OpCodes.Ldarg_1);//arg1: dataSourceChange source, the origine of the binding + il.Emit (OpCodes.Ldstr, bindingDef.SourceMember);//arg2: orig member + il.Emit (OpCodes.Ldarg_2);//arg3: new datasource + il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); + il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//arg4: dest member + il.Emit (OpCodes.Call, typeof(Instantiator).GetMethod("dataSourceReverseBinding", BindingFlags.Static | BindingFlags.NonPublic)); + } + il.MarkLabel (cancel); } il.Emit (OpCodes.Ret); @@ -876,6 +884,56 @@ namespace Crow ctx.emitCachedDelegateHandlerAddition(delDSIndex, typeof(GraphicObject).GetEvent("DataSourceChanged")); } + /// + /// Two way binding for datasource, graphicObj=>dataSource link, datasource value has priority + /// and will be set as init for source property (in emitDataSourceBindings func) + /// + /// Graphic object instance, source of binding + /// Origin member name + /// datasource instance, target of the binding + /// Destination member name + static void dataSourceReverseBinding(IValueChange orig, string origMember, object dest, string destMember){ + Type tOrig = orig.GetType (); + Type tDest = dest.GetType (); + PropertyInfo piOrig = tOrig.GetProperty (origMember); + PropertyInfo piDest = tDest.GetProperty (destMember); + + #region ValueChanged emit + DynamicMethod dm = new DynamicMethod ("dyn_valueChanged" + NewId, + typeof (void), CompilerServices.argsBoundValueChange, true); + ILGenerator il = dm.GetILGenerator (256); + + System.Reflection.Emit.Label endMethod = il.DefineLabel (); + + il.DeclareLocal (typeof(object)); + il.Emit (OpCodes.Nop); + + //load value changed member name onto the stack + il.Emit (OpCodes.Ldarg_2); + il.Emit (OpCodes.Ldfld, CompilerServices.fiMbName); + + //test if it's the expected one + il.Emit (OpCodes.Ldstr, origMember); + il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal + il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals); + il.Emit (OpCodes.Brfalse, endMethod); + //set destination member with valueChanged new value + //load destination ref + il.Emit (OpCodes.Ldarg_0); + //load new value onto the stack + il.Emit (OpCodes.Ldarg_2); + il.Emit (OpCodes.Ldfld, CompilerServices.fiNewValue); + + CompilerServices.emitConvert (il, piOrig.PropertyType, piDest.PropertyType); + + il.Emit (OpCodes.Callvirt, piDest.GetSetMethod ()); + + il.MarkLabel (endMethod); + il.Emit (OpCodes.Ret); + #endregion + + orig.ValueChanged += (EventHandler)dm.CreateDelegate (typeof(EventHandler), dest); + } #endregion /// Emits remove old data source event handler./summary> -- 2.47.3