]> O.S.I.I.S - jp/crow.git/commitdiff
new binding system: DynEvents compilation
authorjpbruyere <jp.bruyere@hotmail.com>
Mon, 12 Oct 2015 07:20:15 +0000 (09:20 +0200)
committerjpbruyere <jp.bruyere@hotmail.com>
Mon, 12 Oct 2015 07:20:15 +0000 (09:20 +0200)
Templates/Expandable.goml
Tests/GOLIBTests.cs
Tests/Interfaces/testCheckbox.goml
Tests/Interfaces/testExpandable.goml
src/CompilerServices/CompilerServices.cs
src/GraphicObjects/Expandable.cs
src/GraphicObjects/GraphicObject.cs
src/GraphicObjects/PrivateContainer.cs
src/GraphicObjects/TemplatedControl.cs

index 844cacb4777af95d766d24fba18cd1ebeb367cf1..1f3c5281e67625740399895429b7189747ceb7c8 100755 (executable)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>\r
-<Border BorderWidth="1" BorderColor="LightGray" Height="{TemplatedHeight}" Width="{TemplatedWidth}" MouseClick="onMouseClick">\r
+<Border BorderWidth="1" BorderColor="LightGray" Height="{TemplatedHeight}" Width="{TemplatedWidth}" \r
+               MouseClick="onMouseClick">\r
        <VerticalStack Height="{TemplatedHeight}" Width="{TemplatedWidth}">\r
                <HorizontalStack Spacing="1" Height="-1" Width="{TemplatedWidth}">\r
                        <Image Margin="2" Width="12" Height="12" Path="{Image}" SvgSub="{SvgSub}"/>\r
index 8ad93184d209c69a0ed9f5240b7ff46e86397719..13576b241f07bdecfef0e74883afc863dc74e0a7 100644 (file)
@@ -35,21 +35,21 @@ namespace test
                int idx = 0;\r
                string[] testFiles = {\r
                        "fps.goml",\r
+                       "testCheckbox.goml",\r
+                       "testExpandable.goml",\r
                        "testContainer.goml",\r
                        "testBorder.goml",\r
                        "testLabel.goml",\r
-                       "testCheckbox.goml",\r
                        "testRadioButton.goml",\r
                        "testSpinner.goml",\r
                        "testPopper.goml",\r
-                       "testExpandable.goml",\r
                        "testGroupBox.goml",\r
-                       "testCombobox.goml",\r
                        "testWindow.goml",\r
                        "testMsgBox.goml",\r
                        "testGrid.goml",\r
-                       "test4.goml",\r
                        "testMeter.goml",\r
+//                     "testCombobox.goml",\r
+//                     "test4.goml",\r
                };\r
 \r
                #region FPS\r
@@ -100,6 +100,7 @@ namespace test
                {\r
                        base.OnLoad (e);\r
                        //this.AddWidget(new test4());\r
+\r
                        LoadInterface("Interfaces/" + testFiles[idx]);\r
                }\r
                protected override void OnUpdateFrame (FrameEventArgs e)\r
index 7f5078a5a105ec736c3de08c1d943c5659d589b6..999d79f91395b061e57cff3c15589ff441323c02 100755 (executable)
@@ -1,3 +1,3 @@
 <?xml version="1.0"?>\r
-<Checkbox Width="100" Height="-1" Caption="Checkbox" Background="DimGray"/>\r
+<Checkbox Width="100" Height="-1" Caption="Checkbox" Background="DimGray" IsChecked="true"/>\r
 \r
index 1627055b0873bc8a3400223d386583dd04a8b02b..5cae7ae60f50db2d4a3d4342f519ac15b747752d 100755 (executable)
@@ -5,5 +5,5 @@
                        <Checkbox Name="chk2" IsChecked="true"/>\r
                        <Checkbox Name="chk3"/>\r
                        <Checkbox Name="chk4"/>\r
-               </VerticalStack>                \r
+               </VerticalStack>\r
 </Expandable>\r
index 44b930e06b15893ce885bc5c7d7fd8244bf106f3..0d13d7bf1d613ddc41bc70c3196b010da4549484 100644 (file)
@@ -17,14 +17,17 @@ namespace go
                PropertyBinding
        }
        public class Binding{
-               public PropertyInfo Property;
+               public MemberInfo SourceMember;
                public string Expression;
 
+               public PropertyInfo Property { get { return SourceMember as PropertyInfo; } }
+               public EventInfo Event { get { return SourceMember as EventInfo; } }
+
                public Binding(){
                }
-               public Binding(PropertyInfo _property, string _expression)
+               public Binding(MemberInfo _sourceMember, string _expression)
                {
-                       Property = _property;
+                       SourceMember = _sourceMember;
                        Expression = _expression;
                }
        }
@@ -45,12 +48,15 @@ namespace go
                public bool FindTarget(GraphicObject source){
                        string member = null;
 
+                       //if binding exp = '{}' => binding is done on datasource
                        if (string.IsNullOrEmpty (Binding.Expression)) {
                                Target = source;
                                Member = null;
                                return true;
                        }
 
+                       //if (Binding.SourceMember.MemberType == MemberTypes.Event)
+
                        string[] bindingExp = Binding.Expression.Split ('/');
 
                        if (bindingExp.Length == 1) {
@@ -81,11 +87,14 @@ namespace go
 
                                string[] bindTrg = bindingExp [ptr].Split ('.');
 
-                               if (bindTrg.Length == 2) {
+                               if (bindTrg.Length == 1)
+                                       member = bindTrg [0];
+                               else if (bindTrg.Length == 2){
                                        tmp = (tmp as GraphicObject).FindByName (bindTrg [0]);
                                        member = bindTrg [1];
                                } else
                                        throw new Exception ("Syntax error in binding, expected 'go dot member'");
+                               
                                Target = tmp;
                        }
                        if (Target == null) {
@@ -266,14 +275,10 @@ namespace go
                        #endregion
 
                        Type[] args = {typeof(object), handlerArgsType};
-                       DynamicMethod dm = new DynamicMethod("dynHandle_" + dynHandleCpt,
+                       DynamicMethod dm = new DynamicMethod("dynHandle",
                                typeof(void), 
                                args, 
                                srcType.Module);
-                       
-                       es.Source.DynamicMethodIds.Add (dynHandleCpt);
-
-                       dynHandleCpt++;
 
                        #region IL generation
                        ILGenerator il = dm.GetILGenerator(256);
@@ -355,7 +360,7 @@ namespace go
                                        }else{
                                                //search if parsing methods are present
                                                MethodInfo lopTryParseMi = lopT.GetMethod("TryParse");
-
+                                               //TODO
                                        }
                                }
 
index f9e81c1a9249256b415d1620c82dc48a3001d6f3..0bc5d06757dc69a843734a544188edbb3a4149f0 100644 (file)
@@ -96,7 +96,7 @@ namespace go
                                }\r
 \r
                                onCollapse (this, null);\r
-                               NotifyValueChanged ("SvgSub", "collapsed");\r
+                               NotifyValueChanged ("SvgSub", "collapsed");\r
             }\r
         }\r
 \r
index 7aba98c83bb45c6687d7653ea13177c3354dbe9d..7ebcaf61c6d860e7b99c6cd12a72db49fc219f60 100644 (file)
@@ -792,16 +792,36 @@ namespace go
                {\r
                        List<ResolvedBinding> resolved = new List<ResolvedBinding> ();\r
                        foreach (Binding b in Bindings) {\r
+                               if (b.SourceMember.MemberType == MemberTypes.Event) {\r
+                                       if (b.Expression.StartsWith("{")){\r
+                                               CompileEventSource(b);\r
+                                               continue;\r
+                                       }\r
+                               }\r
                                ResolvedBinding rb = new ResolvedBinding (b);\r
                                if (!rb.FindTarget (this))\r
                                        continue;\r
+                               if (rb.Binding.SourceMember.MemberType == MemberTypes.Event) {\r
+                                       //register handler for event\r
+                                       MethodInfo mi = rb.Member as MethodInfo;\r
+                                       if (mi == null) {\r
+                                               Debug.WriteLine ("Handler Method not found: " + rb.Binding.Expression);\r
+                                               continue;\r
+                                       }\r
+\r
+                                       MethodInfo addHandler = rb.Binding.Event.GetAddMethod ();\r
+                                       Delegate del = Delegate.CreateDelegate (rb.Binding.Event.EventHandlerType, rb.Target, mi);\r
+                                       addHandler.Invoke (this, new object[] { del });\r
+                                       continue;\r
+                               }\r
                                resolved.Add (rb);                              \r
                        }\r
+                       //group;only one dynMethods by target (valuechanged event source)\r
+                       //changed value name tested in switch\r
                        IEnumerable<ResolvedBinding[]> groupedByTarget = resolved.GroupBy (g => g.Target, g => g, (k, g) => g.ToArray ());\r
                        foreach (ResolvedBinding[] grouped in groupedByTarget) {\r
                                int i = 0;\r
-                               object targetValue = grouped [0].Target;//empty binding exp=> bound to target object by default\r
-                               Type targetType = targetValue.GetType();\r
+                               Type targetType = grouped[0].Target.GetType();\r
                                Type sourceType = this.GetType();\r
 \r
                                DynamicMethod dm = null;\r
@@ -839,8 +859,8 @@ namespace go
                                        jumpTable = new System.Reflection.Emit.Label[grouped.Length];\r
                                        for (i = 0; i < grouped.Length; i++)\r
                                                jumpTable [i] = il.DefineLabel ();\r
-                                       lbMemberName = il.DeclareLocal(typeof(string));\r
-                                       lbValue  = il.DeclareLocal(typeof(object));\r
+                                       il.DeclareLocal(typeof(string));\r
+                                       il.DeclareLocal(typeof(object));\r
 \r
                                        il.Emit(OpCodes.Nop);\r
                                        il.Emit(OpCodes.Ldarg_0);\r
@@ -849,13 +869,13 @@ namespace go
                                        il.Emit(OpCodes.Ldarg_2);\r
                                        FieldInfo fiNewValue = typeof(ValueChangeEventArgs).GetField("NewValue");\r
                                        il.Emit(OpCodes.Ldfld, fiNewValue);\r
-                                       il.Emit(OpCodes.Stloc, lbValue);\r
+                                       il.Emit(OpCodes.Stloc_1);\r
                                        //push name \r
                                        il.Emit(OpCodes.Ldarg_2);\r
                                        FieldInfo fiMbName = typeof(ValueChangeEventArgs).GetField("MemberName");\r
                                        il.Emit(OpCodes.Ldfld, fiMbName);\r
-                                       il.Emit(OpCodes.Stloc, lbMemberName);\r
-                                       il.Emit(OpCodes.Ldloc, lbMemberName);\r
+                                       il.Emit(OpCodes.Stloc_0);\r
+                                       il.Emit(OpCodes.Ldloc_0);\r
                                        il.Emit(OpCodes.Brfalse, endMethod);\r
                                }\r
                                #endregion\r
@@ -863,6 +883,7 @@ namespace go
                                i = 0;\r
                                foreach (ResolvedBinding rb in grouped) {\r
                                        #region initialize target with actual value\r
+                                       object targetValue = null;\r
                                        if (rb.Member != null){\r
                                                if (rb.Member.MemberType == MemberTypes.Property)\r
                                                        targetValue = (rb.Member as PropertyInfo).GetGetMethod ().Invoke (rb.Target, null);\r
@@ -876,10 +897,14 @@ namespace go
                                                                targetValue = mthSrc.Invoke(rb.Target, null);\r
                                                }else\r
                                                        throw new Exception ("unandled source member type for binding");                                                \r
-                                       }\r
+                                       }else if (string.IsNullOrEmpty(rb.Binding.Expression))\r
+                                               targetValue= grouped [0].Target;//empty binding exp=> bound to target object by default\r
                                        //TODO: handle other dest type conversions\r
                                        if (rb.Binding.Property.PropertyType == typeof(string)){\r
-                                               if (targetValue != null)\r
+                                               if (targetValue == null){\r
+                                                       //set default value\r
+\r
+                                               }else\r
                                                        targetValue = targetValue.ToString ();\r
                                        }\r
                                        rb.Binding.Property.GetSetMethod ().Invoke (this, new object[] { targetValue });\r
@@ -889,8 +914,11 @@ namespace go
                                        if (il == null)\r
                                                continue;\r
 \r
-                                       il.Emit (OpCodes.Ldloc, lbMemberName);\r
-                                       il.Emit (OpCodes.Ldstr, rb.Member.Name);\r
+                                       il.Emit (OpCodes.Ldloc_0);\r
+                                       if (rb.Member != null)\r
+                                               il.Emit (OpCodes.Ldstr, rb.Member.Name);\r
+                                       else\r
+                                               il.Emit (OpCodes.Ldstr, rb.Binding.Expression);\r
                                        il.Emit (OpCodes.Callvirt, stringEquals);\r
                                        il.Emit (OpCodes.Brtrue, jumpTable[i]);\r
                                        i++;\r
@@ -905,7 +933,7 @@ namespace go
                                foreach (ResolvedBinding rb in grouped) {\r
 \r
                                        il.MarkLabel (jumpTable [i]);\r
-                                       il.Emit(OpCodes.Ldloc, lbValue);\r
+                                       il.Emit(OpCodes.Ldloc_1);\r
 \r
                                        //by default, target value type is deducted from source member type to allow\r
                                        //memberless binding, if targetMember exists, it will be used to determine target\r
@@ -941,6 +969,125 @@ namespace go
                                addHandler.Invoke(grouped [0].Target, new object[] {del});\r
                        }\r
                }\r
+               /// <summary>\r
+               /// Compile events expression in GOML attributes\r
+               /// </summary>\r
+               /// <param name="es">Event binding details</param>\r
+               public void CompileEventSource(Binding binding)\r
+               {                       \r
+                       Type sourceType = this.GetType();\r
+\r
+                       #region Retrieve EventHandler parameter type\r
+                       MethodInfo evtInvoke = binding.Event.EventHandlerType.GetMethod ("Invoke");\r
+                       ParameterInfo[] evtParams = evtInvoke.GetParameters ();\r
+                       Type handlerArgsType = evtParams [1].ParameterType;\r
+                       #endregion\r
+\r
+                       Type[] args = {typeof(object), typeof(object),handlerArgsType};\r
+                       DynamicMethod dm = new DynamicMethod("dynHandle",\r
+                               typeof(void), \r
+                               args,\r
+                               sourceType);\r
+\r
+\r
+                       #region IL generation\r
+                       ILGenerator il = dm.GetILGenerator(256);\r
+\r
+                       string src = binding.Expression.Trim();\r
+\r
+                       if (! (src.StartsWith("{") || src.EndsWith ("}"))) \r
+                               throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.SourceMember.Name, binding.Expression));\r
+\r
+                       src = src.Substring (1, src.Length - 2);\r
+                       string[] srcLines = src.Split (new char[] { ';' });\r
+\r
+                       foreach (string srcLine in srcLines) {\r
+                               string statement = srcLine.Trim ();\r
+\r
+                               string[] operandes = statement.Split (new char[] { '=' });\r
+                               if (operandes.Length < 2) //not an affectation\r
+                               {\r
+                                       continue;\r
+                               }\r
+                               string lop = operandes [0].Trim ();\r
+                               string rop = operandes [operandes.Length-1].Trim ();\r
+\r
+                               #region LEFT OPERANDES\r
+                               GraphicObject lopObj = this;    //default left operand base object is \r
+                               //the first arg (object sender) of the event handler\r
+\r
+                               string[] lopParts = lop.Split (new char[] { '.' });\r
+                               if (lopParts.Length == 2) {//should search also for member of es.Source\r
+                                       lopObj = this.FindByName (lopParts [0]);\r
+                                       if (lopObj==null)\r
+                                               throw new Exception (string.Format("GOML:Unknown name: {0}", lopParts[0]));\r
+                                       //TODO: should create private member holding ref of lopObj, and emit\r
+                                       //a call to FindByName(lopObjName) during #ctor or in a onLoad func or evt handler\r
+                                       throw new Exception (string.Format("GOML:obj tree ref not yet implemented", lopParts[0]));\r
+                               }else\r
+                                       il.Emit(OpCodes.Ldarg_0);       //load sender ref onto the stack\r
+\r
+                               int i = lopParts.Length -1;\r
+\r
+                               MemberInfo lopMbi = lopObj.GetType().GetMember (lopParts[i])[0];\r
+                               OpCode lopSetOC;\r
+                               dynamic lopSetMbi;\r
+                               Type lopT = null;\r
+                               switch (lopMbi.MemberType) {\r
+                               case MemberTypes.Property:\r
+                                       PropertyInfo lopPi = sourceType.GetProperty (lopParts[i]);\r
+                                       MethodInfo dstMi = lopPi.GetSetMethod ();\r
+                                       lopT = lopPi.PropertyType;\r
+                                       lopSetMbi = dstMi;\r
+                                       lopSetOC = OpCodes.Callvirt;\r
+                                       break;\r
+                               case MemberTypes.Field:\r
+                                       FieldInfo dstFi = sourceType.GetField(lopParts[i]);\r
+                                       lopT = dstFi.FieldType;\r
+                                       lopSetMbi = dstFi;\r
+                                       lopSetOC = OpCodes.Stfld;\r
+                                       break;\r
+                               default:\r
+                                       throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i]));\r
+                               }  \r
+                               #endregion\r
+\r
+                               #region RIGHT OPERANDES\r
+                               if (rop.StartsWith("\'")){\r
+                                       if (!rop.EndsWith("\'"))\r
+                                               throw new Exception (string.Format\r
+                                                       ("GOML:malformed string constant in handler: {0}", rop));       \r
+                                       string strcst = rop.Substring (1, rop.Length - 2);\r
+\r
+                                       il.Emit(OpCodes.Ldstr,strcst);\r
+\r
+                               }else{\r
+                                       //search for a static field in left operand type named 'rop name'\r
+                                       FieldInfo ropFi = lopT.GetField (rop, BindingFlags.Static|BindingFlags.Public);\r
+                                       if (ropFi != null)\r
+                                       {\r
+                                               il.Emit (OpCodes.Ldsfld, ropFi);\r
+                                       }else{\r
+                                               //search if parsing methods are present\r
+                                               MethodInfo lopTryParseMi = lopT.GetMethod("TryParse");\r
+                                               //TODO\r
+                                       }\r
+                               }\r
+\r
+                               #endregion\r
+\r
+                               //emit left operand assignment\r
+                               il.Emit(lopSetOC, lopSetMbi);\r
+                       }\r
+\r
+                       il.Emit(OpCodes.Ret);\r
+\r
+                       #endregion\r
+\r
+                       Delegate del = dm.CreateDelegate(binding.Event.EventHandlerType,this);\r
+                       MethodInfo addHandler = binding.Event.GetAddMethod ();\r
+                       addHandler.Invoke(this, new object[] {del});\r
+               }\r
 \r
                #region IXmlSerializable\r
                public virtual System.Xml.Schema.XmlSchema GetSchema ()\r
@@ -965,13 +1112,7 @@ namespace go
                                        continue;\r
                                }\r
                                if (mi.MemberType == MemberTypes.Event) {\r
-                                       if (!Interface.DontResoveGOML) {\r
-                                               Interface.GOMLResolver.Add (new DynAttribute { \r
-                                                       Source = this, \r
-                                                       Value = attValue,\r
-                                                       MemberName = attName\r
-                                               });\r
-                                       }\r
+                                       this.Bindings.Add (new Binding (mi, attValue));\r
                                        continue;\r
                                }\r
                                if (mi.MemberType == MemberTypes.Property) {\r
index e6f826dc725593e4b6e9748177ef8782b08435f4..6cc444c53e31d0641d612a1cb1c027b3b17501d7 100644 (file)
@@ -73,6 +73,10 @@ namespace go
                        if (child != null)
                                child.ResolveBindings ();
                }
+               protected void ResolveBindingsWithNoRecurse ()
+               {
+                       base.ResolveBindings ();
+               }
                public override GraphicObject FindByName (string nameToFind)
                {
                        if (Name == nameToFind)
index 4dbe21e555454d7d1c3180a4ccdfc019bdf28993..e203c0cf4e6206162ff111c1ab98b19c89c3f7c3 100644 (file)
@@ -105,6 +105,10 @@ namespace go
                        //prevent name searching in template
                        return nameToFind == this.Name ? this : null;
                }
+               public override void ResolveBindings ()
+               {
+                       base.ResolveBindingsWithNoRecurse ();
+               }
                #endregion
 
                protected virtual void loadTemplate(GraphicObject template = null)