From b9ba0efdd5a8580c2828947b4756c68798623854 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Fri, 14 Dec 2018 03:20:19 +0100 Subject: [PATCH] rename AddWidget to Load, prepare debug and optimize reflexion in bindings --- Crow/Crow.NetStd.csproj | 2 +- Crow/Crow.csproj | 2 +- Crow/src/CompilerServices/CompilerServices.cs | 90 ++++++++----------- Crow/src/GraphicObjects/DockStack.cs | 2 +- Crow/src/GraphicObjects/IMLContainer.cs | 2 +- Crow/src/GraphicObjects/TemplatedControl.cs | 4 +- Crow/src/GraphicObjects/Window.cs | 2 +- Crow/src/IML/MemberAddress.cs | 13 ++- Crow/src/Instantiator.cs | 29 +++--- Crow/src/Interface.cs | 10 +-- CrowIDE/src/CrowIDE.cs | 4 +- CrowIDE/src/DesignInterface.cs | 2 +- Tests/BasicTests.cs | 2 +- Tests/Showcase.cs | 4 +- Tests/Tests.csproj | 6 +- 15 files changed, 80 insertions(+), 94 deletions(-) diff --git a/Crow/Crow.NetStd.csproj b/Crow/Crow.NetStd.csproj index 11c06932..0421fa3d 100644 --- a/Crow/Crow.NetStd.csproj +++ b/Crow/Crow.NetStd.csproj @@ -17,7 +17,7 @@ false true Crow - 0.8.0-beta + 0.8.0.1-beta JP Bruyère C# Rapid Open Widget Toolkit diff --git a/Crow/Crow.csproj b/Crow/Crow.csproj index ade2082c..dfdc08f7 100644 --- a/Crow/Crow.csproj +++ b/Crow/Crow.csproj @@ -32,7 +32,7 @@ true false $(SolutionDir)build\Debug - DEBUG_DRAGNDROP0;DEBUG_LOG0;XLIB_BACKEND0;DESIGN_MODE;DEBUG_UPDATE0;DEBUG_FOCUS0;DEBUG_DISPOSE0;TRACE0;DEBUG;MEASURE_TIME;DEBUG_LOAD0;DEBUG_BINDING0;DEBUG_CLIP_RECTANGLE0 + DEBUG_BINDING_FUNC_CALLS0;DEBUG_DRAGNDROP0;DEBUG_LOG0;XLIB_BACKEND0;DESIGN_MODE;DEBUG_UPDATE0;DEBUG_FOCUS0;DEBUG_DISPOSE0;TRACE0;DEBUG;MEASURE_TIME;DEBUG_LOAD0;DEBUG_BINDING0;DEBUG_CLIP_RECTANGLE0 diff --git a/Crow/src/CompilerServices/CompilerServices.cs b/Crow/src/CompilerServices/CompilerServices.cs index ceb09c1a..14d9bb76 100644 --- a/Crow/src/CompilerServices/CompilerServices.cs +++ b/Crow/src/CompilerServices/CompilerServices.cs @@ -97,7 +97,7 @@ namespace Crow.IML internal static MethodInfo miGetDataSource = typeof(GraphicObject).GetProperty("DataSource").GetGetMethod (); internal static EventInfo eiLogicalParentChanged = typeof(GraphicObject).GetEvent("LogicalParentChanged"); - internal static MethodInfo miIFaceLoad = typeof(Interface).GetMethod ("Load", BindingFlags.Instance | BindingFlags.Public); + internal static MethodInfo miIFaceLoad = typeof(Interface).GetMethod ("CreateInstance", BindingFlags.Instance | BindingFlags.Public); internal static MethodInfo miGetITemp = typeof(Interface).GetMethod ("GetItemTemplate", BindingFlags.Instance | BindingFlags.Public); internal static MethodInfo miAddITemp = typeof(Dictionary).GetMethod ("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) }); @@ -287,14 +287,20 @@ namespace Crow.IML #region Reflexion helpers static MemberInfo getMemberInfoWithReflexion(object instance, string member){ - Type t = instance.GetType(); - MemberInfo mi = t.GetMember (member)?.FirstOrDefault(); + Type t = instance.GetType(); +#if DEBUG_BINDING_FUNC_CALLS + Console.WriteLine ($"getMemberInfoWithReflexion ({instance},{member}); type:{t}"); +#endif + MemberInfo mi = t.GetMember (member)?.FirstOrDefault(); if (mi == null) mi = CompilerServices.SearchExtMethod (t, member); return mi; } static MethodInfo getMethodInfoWithReflexion(object instance, string method){ - return instance.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); +#if DEBUG_BINDING_FUNC_CALLS + Console.WriteLine ($"getMethodInfoWithReflexion ({instance},{method}); type:{instance.GetType ()}"); +#endif + return instance.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); } /// /// set value, convert if required @@ -303,7 +309,10 @@ namespace Crow.IML /// Value /// Destination member static void setValueWithReflexion(object dest, object value, string destMember){ - Type destType = null; +#if DEBUG_BINDING_FUNC_CALLS + Console.WriteLine ($"setValueWithReflexion (dest:{dest},value:{value},member:{destMember});"); +#endif + Type destType = null; Type origType = null; object convertedVal = null; @@ -350,7 +359,10 @@ namespace Crow.IML /// default value for valueType data. /// static object getValueWithReflexion(object instance, MemberInfo mi){ - object tmp = null; +#if DEBUG_BINDING_FUNC_CALLS + Console.WriteLine ($"getValueWithReflexion ({instance},{mi});"); +#endif + object tmp = null; Type dstType = null; if (mi == null) return null; @@ -386,35 +398,7 @@ namespace Crow.IML return null; } - /// - /// Gets all extension methods defined in assembly for Type - /// - /// Extension methods enumerable - /// Assembly - /// Extended type to search for - internal static IEnumerable GetExtensionMethods (Assembly assembly, - Type extendedType) - { - IEnumerable query = null; - Type curType = extendedType; - - do { - query = from type in assembly.GetTypes () - where type.IsSealed && !type.IsGenericType && !type.IsNested - from method in type.GetMethods (BindingFlags.Static - | BindingFlags.Public | BindingFlags.NonPublic) - where method.IsDefined (typeof (ExtensionAttribute), false) - where method.GetParameters () [0].ParameterType == curType - select method; - - if (query.Count () > 0) - break; - - curType = curType.BaseType; - } while (curType != null); - - return query; - } + /// /// search for extentions method in entry assembly then in assembly where the type is defined /// @@ -440,16 +424,16 @@ namespace Crow.IML //Console.WriteLine ($"*** search extension method: {t};{methodName} => key={key}"); MethodInfo mi = null; - mi = GetExtensionMethods2 (Assembly.GetEntryAssembly (), t, methodName); + mi = GetExtensionMethods (Assembly.GetEntryAssembly (), t, methodName); if (mi == null) - mi = GetExtensionMethods2 (t.Module.Assembly, t, methodName); + mi = GetExtensionMethods (t.Module.Assembly, t, methodName); //add key even if mi is null to prevent searching again and again for propertyless bindings knownExtMethods.Add (key, mi); return mi; } - static MethodInfo GetExtensionMethods2 (Assembly assembly, Type extendedType, string methodName) + public static MethodInfo GetExtensionMethods (Assembly assembly, Type extendedType, string methodName) { foreach (Type t in assembly.GetTypes ().Where (ty => ty.IsDefined (typeof (ExtensionAttribute), false))) { @@ -504,7 +488,7 @@ namespace Crow.IML } return null; } - #endregion +#endregion /// /// Emits tree parsing command to fetch dest instance starting from orig node @@ -725,9 +709,9 @@ namespace Crow.IML Type t = instance.GetType (); FieldInfo fiEvt = getEventHandlerField (t, eventName); if (fiEvt == null) { - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("RemoveHandlerByName: Event '" + eventName + "' not found in " + instance); - #endif +#endif return; } EventInfo eiEvt = t.GetEvent (eventName); @@ -736,9 +720,9 @@ namespace Crow.IML foreach (Delegate d in multiDel.GetInvocationList()) { if (d.Method.Name == delegateName) { eiEvt.RemoveEventHandler (instance, d); - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName); - #endif +#endif } } } @@ -755,9 +739,9 @@ namespace Crow.IML foreach (Delegate d in multiDel.GetInvocationList()) { if (d.Target == target) { eiEvt.RemoveEventHandler (instance, d); - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName); - #endif +#endif } } } @@ -776,9 +760,9 @@ namespace Crow.IML } internal static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){ - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression); - #endif +#endif Type lopType = null; @@ -787,11 +771,11 @@ namespace Crow.IML else lopType = currentNode.NodeType; - #region Retrieve EventHandler parameter type +#region Retrieve EventHandler parameter type MethodInfo evtInvoke = sourceEvent.EventHandlerType.GetMethod ("Invoke"); ParameterInfo [] evtParams = evtInvoke.GetParameters (); Type handlerArgsType = evtParams [1].ParameterType; - #endregion +#endregion Type [] args = { CompilerServices.TObject, handlerArgsType }; DynamicMethod dm = new DynamicMethod ("dyn_eventHandler", @@ -818,7 +802,7 @@ namespace Crow.IML il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node - #region Left operande +#region Left operande PropertyInfo lopPI = null; //in dyn handler, no datasource binding, so single name in expression are also handled as current node property @@ -828,9 +812,9 @@ namespace Crow.IML lopPI = lopType.GetProperty (lop.Tokens [1]); else lop.emitGetTarget (il, cancel); - #endregion +#endregion - #region RIGHT OPERANDES +#region RIGHT OPERANDES if (rop.IsStringConstant){ il.Emit (OpCodes.Ldstr, rop.Tokens[0]); lop.emitSetProperty (il); @@ -877,7 +861,7 @@ namespace Crow.IML rop.emitGetProperty (il, cancelFinalSet); lop.emitSetProperty (il); } - #endregion +#endregion il.Emit (OpCodes.Br, success); diff --git a/Crow/src/GraphicObjects/DockStack.cs b/Crow/src/GraphicObjects/DockStack.cs index 75f0d2bb..c91b9901 100644 --- a/Crow/src/GraphicObjects/DockStack.cs +++ b/Crow/src/GraphicObjects/DockStack.cs @@ -407,7 +407,7 @@ namespace Crow DockWindow dw = null; string wName = getConfAttrib (conf, ref i); try { - dw = IFace.Load (wName) as DockWindow; + dw = IFace.CreateInstance (wName) as DockWindow; } catch { dw = new DockWindow (IFace); } diff --git a/Crow/src/GraphicObjects/IMLContainer.cs b/Crow/src/GraphicObjects/IMLContainer.cs index 84692284..8ba161a6 100644 --- a/Crow/src/GraphicObjects/IMLContainer.cs +++ b/Crow/src/GraphicObjects/IMLContainer.cs @@ -41,7 +41,7 @@ namespace Crow if (path == value) return; path = value; - this.SetChild (IFace.Load (path)); + this.SetChild (IFace.CreateInstance (path)); NotifyValueChanged ("Path", path); } } diff --git a/Crow/src/GraphicObjects/TemplatedControl.cs b/Crow/src/GraphicObjects/TemplatedControl.cs index a1a11b22..83a24c39 100644 --- a/Crow/src/GraphicObjects/TemplatedControl.cs +++ b/Crow/src/GraphicObjects/TemplatedControl.cs @@ -80,7 +80,7 @@ namespace Crow if (string.IsNullOrEmpty(_template)) loadTemplate (); else - loadTemplate (IFace.Load (_template)); + loadTemplate (IFace.CreateInstance (_template)); } } /// @@ -149,7 +149,7 @@ namespace Crow if (template == null) { if (!IFace.DefaultTemplates.ContainsKey (this.GetType ().FullName)) throw new Exception (string.Format ("No default template found for '{0}'", this.GetType ().FullName)); - this.SetChild (IFace.Load (IFace.DefaultTemplates[this.GetType ().FullName])); + this.SetChild (IFace.CreateInstance (IFace.DefaultTemplates[this.GetType ().FullName])); }else this.SetChild (template); } diff --git a/Crow/src/GraphicObjects/Window.cs b/Crow/src/GraphicObjects/Window.cs index 647286fc..a6155447 100644 --- a/Crow/src/GraphicObjects/Window.cs +++ b/Crow/src/GraphicObjects/Window.cs @@ -456,7 +456,7 @@ namespace Crow public static Window Show (Interface iface, string imlPath, bool modal = false){ lock (iface.UpdateMutex) { - Window w = iface.AddWidget (imlPath) as Window; + Window w = iface.Load (imlPath) as Window; w.Modal = modal; return w; } diff --git a/Crow/src/IML/MemberAddress.cs b/Crow/src/IML/MemberAddress.cs index f27a8b87..a2ef206c 100644 --- a/Crow/src/IML/MemberAddress.cs +++ b/Crow/src/IML/MemberAddress.cs @@ -41,10 +41,6 @@ namespace Crow.IML public PropertyInfo Property { get { return member as PropertyInfo; }} public bool IsTemplateBinding { get { return Address == null ? false : Address.Count == 0; }} -// public string Name { -// get { return memberName; } -// set { memberName = value; } -// } public MemberAddress (NodeAddress _address, string _member, bool findMember = true) { @@ -93,6 +89,9 @@ namespace Crow.IML bool tryFindMember () { +#if DEBUG_BINDING_FUNC_CALLS + Console.WriteLine ($"tryFindMember ({Address},{member})"); +#endif if (member != null) throw new Exception ("member already found"); if (Address == null) @@ -102,13 +101,13 @@ namespace Crow.IML Type t = Address.LastOrDefault ().CrowType; member = t.GetMember (memberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FirstOrDefault (); - #region search for extensions methods if member not found in type +#region search for extensions methods if member not found in type if (member == null && !string.IsNullOrEmpty (memberName)) { Assembly a = Assembly.GetExecutingAssembly (); string mn = memberName; - member = CompilerServices.GetExtensionMethods (a, t).Where (em => em.Name == mn).FirstOrDefault (); + member = CompilerServices.GetExtensionMethods (a, t, mn); } - #endregion +#endregion return member != null; } diff --git a/Crow/src/Instantiator.cs b/Crow/src/Instantiator.cs index f42d1f13..09479f05 100644 --- a/Crow/src/Instantiator.cs +++ b/Crow/src/Instantiator.cs @@ -950,6 +950,9 @@ namespace Crow.IML /// create the valuechanged handler, the datasourcechanged handler and emit event handling /// void emitDataSourceBindings(IMLContext ctx, BindingDefinition bindingDef){ +#if DEBUG_BINDING_FUNC_CALLS + Console.WriteLine ($"emitDataSourceBindings: {bindingDef}"); +#endif DynamicMethod dm = null; ILGenerator il = null; int dmVC = 0; @@ -958,7 +961,7 @@ namespace Crow.IML //will be used as origine value string delName = "dyn_DSvalueChanged" + NewId; if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ - #region create valuechanged method +#region create valuechanged method dm = new DynamicMethod (delName, typeof (void), CompilerServices.argsBoundValueChange, true); @@ -1005,10 +1008,10 @@ namespace Crow.IML //when datasource of source graphic object changed dmVC = dsValueChangedDynMeths.Count; dsValueChangedDynMeths.Add (dm); - #endregion +#endregion } - #region emit dataSourceChanged event handler +#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 //dyn methode. @@ -1052,7 +1055,7 @@ namespace Crow.IML il.Emit (OpCodes.Brfalse, newDSIsNull);//new ds is null } - #region fetch initial Value +#region fetch initial Value if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ il.Emit (OpCodes.Ldarg_2);//load new datasource il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); @@ -1072,7 +1075,7 @@ namespace Crow.IML } CompilerServices.emitConvert (il, piSource.PropertyType); il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ()); - #endregion +#endregion if (!string.IsNullOrEmpty(bindingDef.TargetMember)){ il.MarkLabel(cancelInit); @@ -1107,14 +1110,14 @@ namespace Crow.IML //store dschange delegate in instatiator instance for access while instancing graphic object int delDSIndex = cachedDelegates.Count; cachedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this)); - #endregion +#endregion ctx.emitCachedDelegateHandlerAddition(delDSIndex, CompilerServices.eiDSChange); - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine("\tDataSource ValueChanged: " + delName); Debug.WriteLine("\tDataSource Changed: " + dm.Name); - #endif +#endif } /// /// Two way binding for datasource, graphicObj=>dataSource link, datasource value has priority @@ -1134,11 +1137,11 @@ namespace Crow.IML Debug.WriteLine ("Member '{0}' not found in new DataSource '{1}' of '{2}'", destMember, dest, orig); return; } - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("DS Reverse binding: Member '{0}' found in new DS '{1}' of '{2}'", destMember, dest, orig); - #endif +#endif - #region ValueChanged emit +#region ValueChanged emit DynamicMethod dm = new DynamicMethod ("dyn_valueChanged" + NewId, typeof (void), CompilerServices.argsBoundValueChange, true); ILGenerator il = dm.GetILGenerator (256); @@ -1170,11 +1173,11 @@ namespace Crow.IML il.MarkLabel (endMethod); il.Emit (OpCodes.Ret); - #endregion +#endregion orig.ValueChanged += (EventHandler)dm.CreateDelegate (typeof(EventHandler), dest); } - #endregion +#endregion /// /// search for graphic object type in crow assembly, if not found, diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index f53a2769..621d5549 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -526,10 +526,10 @@ namespace Crow /// /// new instance of graphic object created /// path of the iml file to load - public GraphicObject AddWidget (string path) + public GraphicObject Load (string path) { lock (UpdateMutex) { - GraphicObject tmp = Load (path); + GraphicObject tmp = CreateInstance (path); AddWidget (tmp); return tmp; } @@ -539,7 +539,7 @@ namespace Crow /// /// new instance of graphic object created /// path of the iml file to load - public virtual GraphicObject Load (string path) + public virtual GraphicObject CreateInstance (string path) { try { return GetInstantiator (path).CreateInstance (); @@ -1199,7 +1199,7 @@ namespace Crow volatile bool tooltipVisible = false; protected void initTooltip () { - ToolTipContainer = Load ("#Crow.Tooltip.template"); + ToolTipContainer = CreateInstance ("#Crow.Tooltip.template"); Thread t = new Thread (toolTipThreadFunc); t.IsBackground = true; t.Start (); @@ -1240,7 +1240,7 @@ namespace Crow #region Contextual menu MenuItem ctxMenuContainer; protected void initContextMenus (){ - ctxMenuContainer = Load ("#Crow.ContextMenu.template") as MenuItem; + ctxMenuContainer = CreateInstance ("#Crow.ContextMenu.template") as MenuItem; ctxMenuContainer.LayoutChanged += CtxMenuContainer_LayoutChanged; } diff --git a/CrowIDE/src/CrowIDE.cs b/CrowIDE/src/CrowIDE.cs index b5752ac0..2a791493 100644 --- a/CrowIDE/src/CrowIDE.cs +++ b/CrowIDE/src/CrowIDE.cs @@ -159,7 +159,7 @@ namespace Crow.Coding initCommands (); - GraphicObject go = AddWidget (@"#Crow.Coding.ui.CrowIDE.crow"); + GraphicObject go = Load (@"#Crow.Coding.ui.CrowIDE.crow"); go.DataSource = this; mainDock = go.FindByName ("mainDock") as DockStack; @@ -278,7 +278,7 @@ namespace Crow.Coding GraphicObject g = MainIFace.FindByName (path); if (g != null) return g as Window; - g = MainIFace.AddWidget (path); + g = MainIFace.Load (path); g.Name = path; g.DataSource = dataSource; return g as Window; diff --git a/CrowIDE/src/DesignInterface.cs b/CrowIDE/src/DesignInterface.cs index aa82c34d..4d65e8d2 100644 --- a/CrowIDE/src/DesignInterface.cs +++ b/CrowIDE/src/DesignInterface.cs @@ -81,7 +81,7 @@ namespace Crow.Coding } } - public override GraphicObject Load (string path) + public override GraphicObject CreateInstance (string path) { ProjectFile pi; diff --git a/Tests/BasicTests.cs b/Tests/BasicTests.cs index b8e98567..7db6fad5 100644 --- a/Tests/BasicTests.cs +++ b/Tests/BasicTests.cs @@ -115,7 +115,7 @@ namespace tests //app.AddWidget (@"Interfaces/Divers/testFocus.crow").DataSource = app; //app.AddWidget (@"Interfaces/Divers/testMenu.crow").DataSource = app; //app.AddWidget (@"Interfaces/Divers/testVisibility.crow").DataSource = app; - app.AddWidget (@"Interfaces/Divers/0.crow").DataSource = app; + app.Load (@"Interfaces/Divers/0.crow").DataSource = app; //app.AddWidget (@"Interfaces/Splitter/1.crow").DataSource = app; //app.AddWidget (@"Interfaces/GraphicObject/0.crow").DataSource = app; //app.AddWidget (@"Interfaces/TemplatedContainer/test_Listbox.crow").DataSource = app; diff --git a/Tests/Showcase.cs b/Tests/Showcase.cs index d9802dcf..81f563de 100644 --- a/Tests/Showcase.cs +++ b/Tests/Showcase.cs @@ -45,7 +45,7 @@ namespace tests using (Showcase app = new Showcase ()) { //app.Keyboard.KeyDown += App_KeyboardKeyDown; - GraphicObject g = app.AddWidget ("#Tests.ui.showcase.crow"); + GraphicObject g = app.Load ("#Tests.ui.showcase.crow"); g.DataSource = app; app.crowContainer = g.FindByName ("CrowContainer") as Container; //I set an empty object as datasource at this level to force update when new @@ -85,7 +85,7 @@ namespace tests lock (UpdateMutex) { try { - GraphicObject g = Load(fi.FullName); + GraphicObject g = CreateInstance(fi.FullName); crowContainer.SetChild(g); g.DataSource = this; } diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 5f1c35d0..4f892d45 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -8,7 +8,7 @@ Exe Tests Tests - tests.MainClass + tests.Showcase AnyCPU 0.8.0 $(SolutionDir)build/$(Configuration) @@ -24,11 +24,11 @@ DEBUG;TRACE;MEASURE_TIME $(SolutionDir)build\obj\$(Configuration) $(SolutionDir)build\Debug - + false -- 2.47.3