From: jpbruyere Date: Fri, 23 Dec 2016 10:08:25 +0000 (+0100) Subject: Remove old datasource handler if not null X-Git-Tag: v0.5.1~63^2~10 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=decb4506152e9acd51200a9fb99076eaa4a78f63;p=jp%2Fcrow.git Remove old datasource handler if not null --- diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 7dcfd972..38d4590c 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -802,6 +802,23 @@ namespace Crow } return null; } + /// + /// Removes delegate from event handler by name + /// + public static void RemoveEventHandler(object instance, string eventName, string delegateName){ + Type t = instance.GetType (); + FieldInfo fiEvt = CompilerServices.GetEventHandlerField (t, eventName); + EventInfo eiEvt = t.GetEvent (eventName); + MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate; + if (multiDel != null) { + foreach (Delegate d in multiDel.GetInvocationList()) { + if (d.Method.Name == delegateName) { + eiEvt.RemoveEventHandler (instance, d); + Debug.WriteLine ("event handler removed: " + delegateName + " in " + t.FullName); + } + } + } + } } } diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 52450c34..b7913abd 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -538,12 +538,9 @@ namespace Crow if (dataSource == value) return; - DataSourceChangeEventArgs dse = new DataSourceChangeEventArgs (dataSource, null); - + DataSourceChangeEventArgs dse = new DataSourceChangeEventArgs (dataSource, value); dataSource = value; - dse.NewDataSource = DataSource; - OnDataSourceChanged (this, dse); NotifyValueChanged ("DataSource", DataSource); @@ -1237,87 +1234,6 @@ namespace Crow ParentChanged.Raise (sender, e); } - #region Binding -// public void BindMember(string _member, string _expression){ -// Bindings.Add(new Binding (this, _member, _expression)); -// } -// public virtual void ResolveBindings() -// { -// if (Bindings.Count == 0) -// return; -// #if DEBUG_BINDING -// Debug.WriteLine ("Resolve Bindings => " + this.ToString ()); -// #endif -// -// CompilerServices.ResolveBindings (Bindings); -// } - - /// - /// Remove dynamic delegates by ids from dataSource - /// and delete ref of this in Shared interface refs - /// -// public virtual void ClearBinding(){ -// //dont clear binding if dataSource is not null, -// foreach (Binding b in Bindings) { -// try { -// if (!b.Resolved) -// continue; -// //cancel compiled events -// if (b.Target == null){ -// continue; -// #if DEBUG_BINDING -// Debug.WriteLine("Clear binding canceled for => " + b.ToString()); -// #endif -// } -// if (b.Target.Instance != DataSource){ -// #if DEBUG_BINDING -// Debug.WriteLine("Clear binding canceled for => " + b.ToString()); -// #endif -// continue; -// } -// #if DEBUG_BINDING -// Debug.WriteLine("ClearBinding => " + b.ToString()); -// #endif -// if (string.IsNullOrEmpty (b.DynMethodId)) { -// b.Resolved = false; -// if (b.Source.Member.MemberType == MemberTypes.Event) -// removeEventHandler (b); -// //TODO:check if full reset is necessary -// continue; -// } -// MemberReference mr = null; -// if (b.Target == null) -// mr = b.Source; -// else -// mr = b.Target; -// Type dataSourceType = mr.Instance.GetType(); -// EventInfo evtInfo = dataSourceType.GetEvent ("ValueChanged"); -// FieldInfo evtFi = CompilerServices.GetEventHandlerField (dataSourceType, "ValueChanged"); -// MulticastDelegate multicastDelegate = evtFi.GetValue (mr.Instance) as MulticastDelegate; -// if (multicastDelegate != null) { -// foreach (Delegate d in multicastDelegate.GetInvocationList()) { -// if (d.Method.Name == b.DynMethodId) -// evtInfo.RemoveEventHandler (mr.Instance, d); -// } -// } -// b.Reset (); -// } catch (Exception ex) { -// Debug.WriteLine("\t Error: " + ex.ToString()); -// } -// } -// } -// void removeEventHandler(Binding b){ -// FieldInfo fiEvt = CompilerServices.GetEventHandlerField (b.Source.Instance.GetType(), b.Source.Member.Name); -// MulticastDelegate multiDel = fiEvt.GetValue (b.Source.Instance) as MulticastDelegate; -// if (multiDel != null) { -// foreach (Delegate d in multiDel.GetInvocationList()) { -// if (d.Method.Name == b.Target.Member.Name) -// b.Source.Event.RemoveEventHandler (b.Source.Instance, d); -// } -// } -// } - #endregion - #region IXmlSerializable public virtual System.Xml.Schema.XmlSchema GetSchema () { diff --git a/src/Instantiator.cs b/src/Instantiator.cs index aad49953..e435c0ab 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -352,6 +352,17 @@ namespace Crow } #endregion + void readPropertyBinding (Context ctx, string sourceMember, string expression) + { + NodeAddress sourceNA = ctx.CurrentNodeAddress; + BindingDefinition bindingDef = splitBindingExp (sourceNA, sourceMember, expression); + + if (bindingDef.IsDataSourceBinding)//bind on data source + emitDataSourceBindings (ctx, sourceMember, bindingDef.TargetMember); + else + ctx.StorePropertyBinding (bindingDef); + } + string[] splitOnSemiColumnOutsideAccolades (string expression){ List exps = new List(); int accCount = 0; @@ -376,16 +387,6 @@ namespace Crow exps.Add(expression); return exps.ToArray (); } - void readPropertyBinding (Context ctx, string sourceMember, string expression) - { - NodeAddress sourceNA = ctx.CurrentNodeAddress; - BindingDefinition bindingDef = splitBindingExp (sourceNA, sourceMember, expression); - - if (bindingDef.IsDataSourceBinding)//bind on data source - emitDataSourceBindings (ctx, sourceMember, bindingDef.TargetMember); - else - ctx.StorePropertyBinding (bindingDef); - } /// /// Gets the node adress from binding expression splitted with '/' starting at a given node /// @@ -458,6 +459,7 @@ namespace Crow } #endregion + #region Event Bindings /// /// Compile events expression in IML attributes, and store the result in the instanciator /// Those handlers will be bound when instatiing @@ -587,13 +589,14 @@ namespace Crow cachedDelegates.Add (dm.CreateDelegate (sourceEvent.EventHandlerType)); ctx.emitCachedDelegateHandlerAddition(dmIdx, sourceEvent); } + /// Emits handler method bindings void emitHandlerBinding (Context ctx, EventInfo sourceEvent, string expression){ NodeAddress currentNode = ctx.CurrentNodeAddress; BindingDefinition bindingDef = splitBindingExp (currentNode, sourceEvent.Name, expression); if (bindingDef.IsTemplateBinding | bindingDef.IsDataSourceBinding) { //we need to bind datasource method to source event - DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler", + DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler" + NewId, typeof(void), CompilerServices.argsBoundDSChange, true); @@ -604,6 +607,8 @@ namespace Crow il.Emit (OpCodes.Nop); + emitRemoveOldDataSourceHandler(il, sourceEvent.Name, bindingDef.TargetMember); + //fetch method in datasource and test if it exist il.Emit (OpCodes.Ldarg_2);//load new datasource il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); @@ -617,7 +622,7 @@ namespace Crow il.Emit (OpCodes.Brfalse, cancel); - il.Emit (OpCodes.Ldarg_1);//load datasource change source where the event handler is as 1st arg of handler.add + il.Emit (OpCodes.Ldarg_1);//load datasource change source where the event is as 1st arg of handler.add if (bindingDef.IsTemplateBinding)//fetch source instance with address CompilerServices.emitGetInstance (il, bindingDef.SourceNA); @@ -645,12 +650,15 @@ namespace Crow if (bindingDef.IsDataSourceBinding) ctx.emitCachedDelegateHandlerAddition (delDSIndex, typeof(GraphicObject).GetEvent ("DataSourceChanged")); - else //template handler binding + else //template handler binding, will be added to root parentChanged templateCachedDelegateIndices.Add (delDSIndex); } else {//normal in tree handler binding, store until tree is complete (end of parse) } } + #endregion + + #region Property Bindings /// /// Create and store in the instanciator the ValueChanged delegates /// those delegates uses grtree functions to set destination value so they don't @@ -707,9 +715,9 @@ namespace Crow #region check if new parent is null cancel = ilPC.DefineLabel (); - ilPC.Emit (OpCodes.Ldarg_2);//load new parent + ilPC.Emit (OpCodes.Ldarg_2);//load datasource change arg ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); - ilPC.Emit (OpCodes.Brfalse, cancel);//new parent is null + ilPC.Emit (OpCodes.Brfalse, cancel);//new ds is null #endregion int i = 0; @@ -913,9 +921,10 @@ namespace Crow PropertyInfo piOrigine = ctx.CurrentNodeType.GetProperty(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)){ #region create valuechanged method - dm = new DynamicMethod ("dyn_DSvalueChanged", + dm = new DynamicMethod (delName, typeof (void), CompilerServices.argsBoundValueChange, true); @@ -957,7 +966,6 @@ namespace Crow //vc dyn meth is stored in a cached list, it will be bound to datasource only //when datasource of source graphic object changed dmVC = dsValueChangedDynMeths.Count; - //Delegate tmp = dm.CreateDelegate(typeof(EventHandler), this); dsValueChangedDynMeths.Add (dm); #endregion } @@ -980,11 +988,12 @@ namespace Crow il.Emit (OpCodes.Nop); + emitRemoveOldDataSourceHandler(il, "ValueChanged", delName); + if (!string.IsNullOrEmpty(dataSourceMember)){ - //first test if datasource is null - il.Emit (OpCodes.Ldarg_2);//load new datasource + il.Emit (OpCodes.Ldarg_2);//load datasource change arg il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); - il.Emit (OpCodes.Brfalse, cancel); + il.Emit (OpCodes.Brfalse, cancel);//new ds is null } #region fetch initial Value @@ -1030,6 +1039,25 @@ namespace Crow ctx.emitCachedDelegateHandlerAddition(delDSIndex, typeof(GraphicObject).GetEvent("DataSourceChanged")); } + #endregion + + /// Emits remove old data source event handler./summary> + void emitRemoveOldDataSourceHandler(ILGenerator il, string eventName, string delegateName){ + System.Reflection.Emit.Label cancel = il.DefineLabel (); + + il.Emit (OpCodes.Ldarg_2);//load old parent + il.Emit (OpCodes.Ldfld, typeof (DataSourceChangeEventArgs).GetField ("OldDataSource")); + il.Emit (OpCodes.Brfalse, cancel);//old parent is null + + //remove handler + il.Emit (OpCodes.Ldarg_2);//1st arg load old datasource + il.Emit (OpCodes.Ldfld, typeof (DataSourceChangeEventArgs).GetField ("OldDataSource")); + il.Emit (OpCodes.Ldstr, eventName);//2nd arg event name + il.Emit (OpCodes.Ldstr, delegateName);//3d arg: delegate name + il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("RemoveEventHandler", BindingFlags.Static | BindingFlags.Public)); + il.MarkLabel(cancel); + } + } }