]> O.S.I.I.S - jp/crow.git/commitdiff
Remove old datasource handler if not null
authorjpbruyere <jp.bruyere@hotmail.com>
Fri, 23 Dec 2016 10:08:25 +0000 (11:08 +0100)
committerjpbruyere <jp.bruyere@hotmail.com>
Fri, 23 Dec 2016 11:46:00 +0000 (12:46 +0100)
src/CompilerServices/CompilerServices.cs
src/GraphicObjects/GraphicObject.cs
src/Instantiator.cs

index 7dcfd9724c7c3430d9f4917ffa4122f5b4d48fdf..38d4590cb0c1a879154348b3215f9d96c94d29cb 100644 (file)
@@ -802,6 +802,23 @@ namespace Crow
                        }
                        return null;
                }
+               /// <summary>
+               /// Removes delegate from event handler by name
+               /// </summary>
+               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);
+                                       }
+                               }
+                       }
+               }
        }
 }
 
index 52450c34dac7ad08b8baaef68704ebb8d3eb69e8..b7913abd33f979dc810ce608d44c597c1549b3ed 100644 (file)
@@ -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);
-//             }
-
-               /// <summary>
-               /// Remove dynamic delegates by ids from dataSource
-               ///  and delete ref of this in Shared interface refs
-               /// </summary>
-//             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 ()
                {
index aad49953aed6d548260a4995330e39ffb8268bff..e435c0abe5f2e6b0b16bd25931fd0ea3cfe5ee5c 100644 (file)
@@ -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<String> exps = new List<string>();
                        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);
-               }
                /// <summary>
                /// Gets the node adress from binding expression splitted with '/' starting at a given node
                /// </summary>
@@ -458,6 +459,7 @@ namespace Crow
                }
                #endregion
 
+               #region Event Bindings
                /// <summary>
                /// 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);
                }
+               /// <summary> Emits handler method bindings </summary>
                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
                /// <summary>
                /// 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<ValueChangeEventArgs>), 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
+
+               /// <summary> 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);
+               }
+
        }
 }