2005-07-05 Iain McCoy <iain@mccoy.id.au>
authorIain McCoy <iainmc@mono-cvs.ximian.com>
Tue, 5 Jul 2005 08:55:40 +0000 (08:55 -0000)
committerIain McCoy <iainmc@mono-cvs.ximian.com>
Tue, 5 Jul 2005 08:55:40 +0000 (08:55 -0000)
        * Mono.Windows.Serialization/XamlParser.cs,
          Mono.Windows.Serialization/XamlWriter.cs,
          Mono.Windows.Serialization/CodeWriter.cs: add support for delegate
          properties and for events
        * Mono.Windows.Serialization/XamlParser.cs,
          Mono.Windows.Serialization/XamlWriter.cs,
          Mono.Windows.Serialization/CodeWriter.cs,
          Mono.Windows.Serialization/Mapper.cs: tighten up types so that Type
          and PropertyInfo are passed instead of strings
        * README: describe the demo as it currently is
        * demo/TestVocab/ConsoleWriter.cs: delegates demonstration
        * demo/TestVocab/ConsoleApp.cs: events demonstration
        * demo/test.xaml: include delegates and events in demonstration

svn path=/trunk/mcs/; revision=46932

mcs/class/PresentationFramework/ChangeLog
mcs/class/PresentationFramework/Mono.Windows.Serialization/CodeWriter.cs
mcs/class/PresentationFramework/Mono.Windows.Serialization/Mapping.cs
mcs/class/PresentationFramework/Mono.Windows.Serialization/XamlParser.cs
mcs/class/PresentationFramework/Mono.Windows.Serialization/XamlWriter.cs
mcs/tools/xamlc/ChangeLog
mcs/tools/xamlc/README
mcs/tools/xamlc/demo/TestVocab/ConsoleApp.cs
mcs/tools/xamlc/demo/TestVocab/ConsoleWriter.cs
mcs/tools/xamlc/demo/test.xaml

index 32fee625ed51b081817be4710e40d147f39d8d42..645b2b023dfe6eb8afa3918e73603caf249b4581 100644 (file)
@@ -1,3 +1,15 @@
+2005-07-05  Iain McCoy  <iain@mccoy.id.au>
+
+       * Mono.Windows.Serialization/XamlParser.cs,
+         Mono.Windows.Serialization/XamlWriter.cs,
+         Mono.Windows.Serialization/CodeWriter.cs: add support for delegate
+         properties and for events
+       * Mono.Windows.Serialization/XamlParser.cs,
+         Mono.Windows.Serialization/XamlWriter.cs,
+         Mono.Windows.Serialization/CodeWriter.cs,
+         Mono.Windows.Serialization/Mapper.cs: tighten up types so that Type
+         and PropertyInfo are passed instead of strings
+
 2005-07-03  Iain McCoy  <iain@mccoy.id.au>
 
        * Mono.Windows.Serialization/XamlParser.cs: added support for Code
index 7e2db10bc280c5e850dd4d6fbbf72e80769dea5f..7f52ea08a13e73b1f04c7405752ad6467db8445c 100644 (file)
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Reflection;
 using System.IO;
 using System.Collections;
 using System.CodeDom;
@@ -53,9 +54,8 @@ namespace Mono.Windows.Serialization {
        
                // pushes: a CodeVariableReferenceExpression to the present
                //      instance
-               public void CreateTopLevel(string parentName, string className)
+               public void CreateTopLevel(Type parent, string className)
                {
-                       Type parent = Type.GetType(parentName);
                        int endNamespaceName = className.LastIndexOf(".");
                        string clrNamespace;
                        if (endNamespaceName < 0)
@@ -77,9 +77,8 @@ namespace Mono.Windows.Serialization {
 
                // bottom of stack holds CodeVariableReferenceExpression
                // pushes a reference to the new current type
-               public void CreateObject(string typeName)
+               public void CreateObject(Type type)
                {
-                       Type type = Type.GetType(typeName);
                        string varName = Char.ToLower(type.Name[0]) + type.Name.Substring(1);
                        // make sure something sensible happens when class
                        // names start with a lowercase letter
@@ -109,37 +108,46 @@ namespace Mono.Windows.Serialization {
 
                // top of stack is a reference to an object
                // pushes a reference to the property
-               public void CreateProperty(string propertyName)
+               public void CreateProperty(PropertyInfo property)
                {
                        CodePropertyReferenceExpression prop = new CodePropertyReferenceExpression(
                                        (CodeExpression)objects[objects.Count - 1],
-                                       propertyName);
+                                       property.Name);
                        objects.Add(prop);
                }
 
+               // top of stack is a reference to an object
+               // pushes a reference to the event
+               public void CreateEvent(EventInfo evt)
+               {
+                       CodeEventReferenceExpression expr = new CodeEventReferenceExpression(
+                                       (CodeExpression)objects[objects.Count - 1],
+                                       evt.Name);
+                       objects.Add(expr);
+               }
+
                // top of stack is a reference to an object
                // pushes the name of the instance to attach to, the name of 
                //   the property, and a reference to an object
-               public void CreateAttachedProperty(string attachedTo, string propertyName, string typeName)
+               public void CreateAttachedProperty(Type attachedTo, string propertyName, Type propertyType)
                {
-                       Type t = Type.GetType(typeName);
-                       Type typeAttachedTo = Type.GetType(attachedTo);
-
-                       string name = "temp";
-                       if (tempIndex != 0)
-                               name += tempIndex;
-                       CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement(t, name);
+                       string varName = "temp";
+                       if (tempIndex != 0) {
+                               varName += tempIndex;
+                               tempIndex += 1;
+                       }
+                       CodeVariableDeclarationStatement decl = new CodeVariableDeclarationStatement(propertyType, varName);
                        constructor.Statements.Add(decl);
 
 
                        CodeMethodInvokeExpression call = new CodeMethodInvokeExpression(
-                                       new CodeTypeReferenceExpression(typeAttachedTo),
+                                       new CodeTypeReferenceExpression(attachedTo),
                                        "Set" + propertyName,
                                        (CodeExpression)objects[objects.Count - 1],
-                                       new CodeVariableReferenceExpression(name));
+                                       new CodeVariableReferenceExpression(varName));
 
                        objects.Add(call);
-                       objects.Add(new CodeVariableReferenceExpression(name));
+                       objects.Add(new CodeVariableReferenceExpression(varName));
                }
 
                // pops 2 items: the name of the property, and the object to attach to
@@ -162,20 +170,47 @@ namespace Mono.Windows.Serialization {
                        constructor.Statements.Add(call);
                }
 
+               // top of stack is reference to an event
+               public void CreateEventDelegate(string functionName, Type eventDelegateType)
+               {
+                       CodeExpression expr = new CodeObjectCreateExpression(
+                                       eventDelegateType,
+                                       new CodeMethodReferenceExpression(
+                                                       new CodeThisReferenceExpression(),
+                                                       functionName));
+                       CodeAttachEventStatement attach = new CodeAttachEventStatement(
+                                       (CodeEventReferenceExpression)objects[objects.Count - 1],
+                                       expr);
+                       constructor.Statements.Add(attach);
+
+               }
                // top of stack is reference to a property
-               public void CreatePropertyText(string text, string converter)
+               public void CreatePropertyDelegate(string functionName, Type propertyType)
                {
-                       CreateAttachedPropertyText(text, converter);
+                       CodeExpression expr = new CodeObjectCreateExpression(
+                                       propertyType,
+                                       new CodeMethodReferenceExpression(
+                                                       new CodeThisReferenceExpression(),
+                                                       functionName));
+                       CodeAssignStatement assignment = new CodeAssignStatement(
+                                       (CodeExpression)objects[objects.Count - 1],
+                                       expr);
+                       constructor.Statements.Add(assignment);
                }
-               public void CreateAttachedPropertyText(string text, string converter)
+               // top of stack is reference to a property
+               public void CreatePropertyText(string text, Type propertyType, Type converterType)
+               {
+                       CreateAttachedPropertyText(text, propertyType, converterType);
+               }
+               // top of stack is reference to an attached property
+               public void CreateAttachedPropertyText(string text, Type propertyType, Type converterType)
                {
                        CodeExpression expr = new CodePrimitiveExpression(text);
-                       if (converter != null) {
-                               Type t = Type.GetType(converter);
+                       if (converterType != null) {
                                expr = new CodeCastExpression(
-                                               new CodeTypeReference(typeof(int)),
+                                               new CodeTypeReference(propertyType),
                                                new CodeMethodInvokeExpression(
-                                                               new CodeObjectCreateExpression(t),
+                                                               new CodeObjectCreateExpression(converterType),
                                                                "ConvertFromString",
                                                                expr));
                        }
@@ -195,6 +230,11 @@ namespace Mono.Windows.Serialization {
                {
                        objects.RemoveAt(objects.Count - 1);
                }
+               
+               public void EndEvent()
+               {
+                       objects.RemoveAt(objects.Count - 1);
+               }
 
                public void Finish()
                {
index 07d9d6eb02b5a24b17d86334ab4340c2f8a058c3..256fafd13b09ec0a51e65c3606fc10ae6b8818e0 100644 (file)
@@ -42,7 +42,7 @@ namespace Mono.Windows.Serialization {
                        mappings[mapping.XmlNamespace] = mapping;
                }
 
-               public string Resolve(string clrNamespace, string classname)
+               public Type Resolve(string clrNamespace, string classname)
                {
                        return ((Mapping)mappings[clrNamespace]).Resolve(classname);
                }
@@ -116,14 +116,14 @@ namespace Mono.Windows.Serialization {
                        get { return xmlNamespace; }
                }
 
-               public string Resolve(string className)
+               public Type Resolve(string className)
                {
                        Assembly assembly = Assembly.Load(assemblyName);
                        Type type = assembly.GetType(clrNamespace + "." + className);
                        if (type == null) {
                                throw new MappingException(className, XmlNamespace);
                        } else {
-                               return type.AssemblyQualifiedName;
+                               return type;
                        }
                }
        }
index 6939bcc8236010d80c575e2cea72cc3f1402bb6d..a1a9dd62962ac1fb8bc51d6a2fb4839f36ca17a7 100644 (file)
@@ -140,6 +140,8 @@ namespace Mono.Windows.Serialization {
                // the given type
                bool isNameOfAncestorClass(string name, Type t)
                {
+                       if (name == "object")
+                               return true;
                        while (t.BaseType != null) {
                                if (t.Name == name)
                                        return true;
@@ -162,14 +164,16 @@ namespace Mono.Windows.Serialization {
                                writer.CreateElementText(reader.Value);
                        } else if (currentState.type == CurrentType.AttachedProperty) {
                                DependencyProperty dp = (DependencyProperty)currentState.obj;
-                               writer.CreateAttachedPropertyText(reader.Value, getTypeConverter(dp.PropertyType));
+                               writer.CreateAttachedPropertyText(reader.Value, dp.PropertyType, 
+                                               getTypeConverter(dp.PropertyType));
                        } else {
                                PropertyInfo prop = (PropertyInfo)currentState.obj;
-                               writer.CreatePropertyText(reader.Value, getTypeConverter(prop.PropertyType));
+                               writer.CreatePropertyText(reader.Value, prop.PropertyType,
+                                               getTypeConverter(prop.PropertyType));
                        }
                }
                
-               string getTypeConverter(Type fromType)
+               Type getTypeConverter(Type fromType)
                {
                        // TODO: this business setting assembly is frankly
                        // grotesque. It should just be something along the
@@ -188,9 +192,8 @@ namespace Mono.Windows.Serialization {
                                return null;
                        string converterName = "System.ComponentModel." + fromType.Name + "Converter,System.dll";
                        Type converter = assembly.GetType(converterName);
-                       return converter.AssemblyQualifiedName;
-                       // TODO: catch NullReferenceException and do something
-                       // cool
+                       return converter;
+                       // TODO: check if converter == null and do something cool
                }
 
                
@@ -199,6 +202,7 @@ namespace Mono.Windows.Serialization {
                        // preconditions: currentState.Type == Object
                        Type currentType = (Type)currentState.obj;
                        PropertyInfo prop = currentType.GetProperty(propertyName);
+
                        if (prop == null) {
                                Console.WriteLine("Property " + propertyName + " not found on " + currentType.Name);
                                return;
@@ -210,7 +214,7 @@ namespace Mono.Windows.Serialization {
                        currentState.type = CurrentType.Property;
                        currentState.obj = prop;
 
-                       writer.CreateProperty(propertyName);
+                       writer.CreateProperty(prop);
 
                        if (reader.HasAttributes) {
                                Console.WriteLine("Property node should not have attributes");
@@ -247,24 +251,23 @@ namespace Mono.Windows.Serialization {
                        currentState.obj = dp;
                        currentState.type = CurrentType.AttachedProperty;
 
-                       writer.CreateAttachedProperty(typeAttachedTo.AssemblyQualifiedName, 
-                                       propertyName, 
-                                       dp.PropertyType.AssemblyQualifiedName);
+                       writer.CreateAttachedProperty(typeAttachedTo, propertyName, dp.PropertyType);
                }
 
                void parseObjectElement()
                {
-                       string parentName, objectName = null;
+                       Type parent;
+                       string objectName = null;
                        bool isEmpty = reader.IsEmptyElement;
                        
-                       parentName = mapper.Resolve(reader.NamespaceURI, reader.Name);
+                       parent = mapper.Resolve(reader.NamespaceURI, reader.Name);
                        objectName = reader.GetAttribute("Class", XAML_NAMESPACE);
-                       if (Type.GetType(parentName).GetInterface("System.Windows.Serialization.IAddChild") == null)
+                       if (parent.GetInterface("System.Windows.Serialization.IAddChild") == null)
                                {} //TODO: throw exception
                        if (currentState == null) {
-                               createTopLevel(parentName, objectName);
+                               createTopLevel(parent.AssemblyQualifiedName, objectName);
                        } else {
-                               addChild(parentName);
+                               addChild(parent);
                        }
                        
                        if (reader.MoveToFirstAttribute()) {
@@ -281,28 +284,70 @@ namespace Mono.Windows.Serialization {
                        }
                        
 
-                       if (isEmpty)
+                       if (isEmpty) {
                                writer.EndObject();
+                               pop();
+                       }
+               }
+
+               void createTopLevel(string parentName, string objectName)
+               {
+                       Type t = Type.GetType(parentName);
+                       currentState = new ParserState();
+                       currentState.type = CurrentType.Object;
+                       currentState.obj = t;
+                       if (objectName == null) {
+                               objectName = "derived" + t.Name;
+                       }
+                       writer.CreateTopLevel(t, objectName);
                }
+
+               void addChild(Type type)
+               {
+                       writer.CreateObject(type);
+                       oldStates.Add(currentState);
+                       currentState = new ParserState();
+                       currentState.type = CurrentType.Object;
+                       currentState.obj = type;
+               }
+
                
                void parseLocalPropertyAttribute()
                {
                        string propertyName = reader.LocalName;
                        Type currentType = (Type)currentState.obj;
                        PropertyInfo prop = currentType.GetProperty(propertyName);
+                       if (parsedAsEventProperty(currentType, propertyName))
+                               return;
                        if (prop == null) {
                                Console.WriteLine("Property " + propertyName + " not found on " + currentType.Name);
                                return;
                                // TODO: throw exception
                        }
 
-                       writer.CreateProperty(propertyName);
-                       writer.CreatePropertyText(reader.Value, getTypeConverter(prop.PropertyType));
+                       writer.CreateProperty(prop);
 
-                       parseEndElement();
+                       if (prop.PropertyType.IsSubclassOf(typeof(Delegate)))
+                               writer.CreatePropertyDelegate(reader.Value, prop.PropertyType);
+                       else
+                               writer.CreatePropertyText(reader.Value, prop.PropertyType, getTypeConverter(prop.PropertyType));
+                       
+                       writer.EndProperty();
+               }
+               
+               bool parsedAsEventProperty(Type currentType, string eventName)
+               {
+                       EventInfo evt = currentType.GetEvent(eventName);
+                       if (evt == null)
+                               return false;
+                       writer.CreateEvent(evt);
+                       writer.CreateEventDelegate(reader.Value, evt.EventHandlerType);
+                       writer.EndEvent();
+                       return true;
                }
 
 
+
                void parseContextPropertyAttribute()
                {
                        throw new NotImplementedException("parseContextPropertyAttribute");
@@ -319,7 +364,11 @@ namespace Mono.Windows.Serialization {
                        else if (currentState.type == CurrentType.AttachedProperty)
                                writer.EndAttachedProperty();
                                
+                       pop();
+               }
 
+               void pop()
+               {
                        if (oldStates.Count == 0) {
                                currentState = null;
                                writer.Finish();
@@ -328,27 +377,8 @@ namespace Mono.Windows.Serialization {
                        int lastIndex = oldStates.Count - 1;
                        currentState = (ParserState)oldStates[lastIndex];
                        oldStates.RemoveAt(lastIndex);
-               }
 
-               void createTopLevel(string parentName, string objectName)
-               {
-                       Type t = Type.GetType(parentName);
-                       currentState = new ParserState();
-                       currentState.type = CurrentType.Object;
-                       currentState.obj = t;
-                       if (objectName == null) {
-                               objectName = "derived" + t.Name;
-                       }
-                       writer.CreateTopLevel(parentName, objectName);
                }
 
-               void addChild(string className)
-               {
-                       writer.CreateObject(className);
-                       oldStates.Add(currentState);
-                       currentState = new ParserState();
-                       currentState.type = CurrentType.Object;
-                       currentState.obj = Type.GetType(className);
-               }
        }
 }
index a4c956a4e8f9dbffe26de9aa34949df7a384cae1..9efbc9b501168f2ca2c0b15cc3d0d2d33771a957 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System;
+using System.Reflection;
+
 namespace Mono.Windows.Serialization {
        public interface XamlWriter {
-               void CreateTopLevel(string parentName, string className);
+               void CreateTopLevel(Type parent, string className);
 
-               void CreateObject(string typeName);
+               void CreateObject(Type type);
                void CreateElementText(string text);
                void EndObject();
 
-               void CreateProperty(string propertyName);
-               void CreatePropertyText(string text, string converter);
+               void CreateProperty(PropertyInfo property);
+               void CreatePropertyText(string text, Type propertyType, Type converterType);
+               void CreatePropertyDelegate(string functionName, Type propertyType);
                void EndProperty();
-               
-               void CreateAttachedProperty(string attachedTo, string propertyName, string typeName);
-               void CreateAttachedPropertyText(string text, string converter);
+       
+
+               void CreateEvent(EventInfo evt);
+               void CreateEventDelegate(string functionName, Type eventDelegateType);
+               void EndEvent();
+
+               void CreateAttachedProperty(Type attachedTo, string propertyName, Type propertyType);
+               void CreateAttachedPropertyText(string text, Type propertyType, Type converterType);
                void EndAttachedProperty();
 
                void CreateCode(string code);
index c9f27bf066cf1f523a88ab19834342c8405eaf62..10af8237b11b6baa1be010320200ddef38825768 100644 (file)
@@ -1,3 +1,10 @@
+2005-07-05  Iain McCoy  <iain@mccoy.id.au>
+
+       * README: describe the demo as it currently is
+       * demo/TestVocab/ConsoleWriter.cs: delegates demonstration
+       * demo/TestVocab/ConsoleApp.cs: events demonstration
+       * demo/test.xaml: include delegates and events in demonstration
+
 2005-07-03  Iain McCoy  <iain@mccoy.id.au>
        * demo/Makefile: made more useful - just do "make run" and it should
        all happen
index 114d9a7aeabc4c7353a3aea4516511eec7b6ce7e..f4e39131de4cab59bb6787b8ecbbc205ae2b9f0f 100644 (file)
@@ -26,6 +26,12 @@ cd ../../tools/xamlc
 make install
 
 That will get everything compiled. There's a demo in the mcs/tools/xamlc/demo
-directory; to run it, cd into that directory and run make. Look at the
-resulting test.xaml.out file. That Makefile obviously has a sample invocation
-of xamlc.exe.
+directory; to run it, cd into that directory and do "make run". Stuff should 
+happen, along the lines of a program test.exe being generated and run to 
+produce this output:
+IT BEGINS!
+Hello World
+Goodbye.
+Goodbye.
+Goodbye.
+You should be able to see how that's made from the included test.xaml file
index 4d75d368d824510257daf18fd971929fb4ca0a53..1a022df95641c322eb8fd012aca88220a0ee1863 100644 (file)
@@ -4,8 +4,12 @@ using System.Windows;
 using System.Windows.Serialization;
 
 namespace Xaml.TestVocab.Console {
+       public delegate void SomethingHappenedHandler();
        public class ConsoleApp : IAddChild {
                private ArrayList actions = new ArrayList();
+
+               public event SomethingHappenedHandler SomethingHappened;
+               
                public void AddText(string Text)
                {
                        actions.Add(new ConsoleWriter(Text));
@@ -23,8 +27,12 @@ namespace Xaml.TestVocab.Console {
                {
                        foreach (IConsoleAction action in actions) {
                                int reps = GetRepetitions((DependencyObject)action);
-                               for (int i = 0; i < reps; i++)
+                               for (int i = 0; i < reps; i++) {
+                                       SomethingHappenedHandler s = SomethingHappened;
+                                       if (s != null)
+                                               s();
                                        action.Run();
+                               }
                        }
                }
 
index e57a722ee4f005be9997863de7e8572c76411c1e..ad636e08ad34b49d0df5882ae8324deb340aebc8 100644 (file)
@@ -3,8 +3,11 @@ using System.Windows;
 using System.Windows.Serialization;
 
 namespace Xaml.TestVocab.Console {
+       public delegate string Filter(string s);
+       
        public class ConsoleWriter : DependencyObject, IAddChild, IConsoleAction {
                string text;
+               private Filter filter;
 
                public ConsoleWriter()
                {
@@ -20,6 +23,10 @@ namespace Xaml.TestVocab.Console {
                        get { return text; }
                        set { text = value; }
                }
+               public Filter Filter {
+                       get { return Filter; }
+                       set { filter = value; }
+               }
 
                public void AddText(string text)
                {
@@ -34,7 +41,12 @@ namespace Xaml.TestVocab.Console {
                
                public void Run()
                {
-                       System.Console.WriteLine(text);
+                       Filter f = filter;
+                       string s = text;
+                       // apply filter, if it exists
+                       if (f != null)
+                               s = f(s);
+                       System.Console.WriteLine(s);
                }
        }
 }
index 2aeceeaab1c0528fc0180e21755424e1bcb3a643..987be65badfbbff76ee4a2317aef2f6d1149ac57 100644 (file)
@@ -2,9 +2,11 @@
 
 <ConsoleApp xmlns="console" 
                xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005" 
-               x:Class="DemoConsoleApp">
+               x:Class="DemoConsoleApp"
+               SomethingHappened="printHi">
        <ConsoleWriter>IT BEGINS!</ConsoleWriter>
        <ConsoleWriter Text="Hello World" />
+       <ConsoleWriter Text="I'm surrounded!" Filter="stringFilter" />
        <ConsoleWriter>
                <ConsoleApp.Repetitions>3</ConsoleApp.Repetitions>
                <ConsoleWriter.Text>Goodbye.</ConsoleWriter.Text>
                        Xaml.TestVocab.Console.ConsoleApp c = new DemoConsoleApp();
                        c.Run();
                }
+
+               private string stringFilter(string s)
+               {
+                       return "YYY" + s + "ZZZ";
+               }
+
+               private void printHi()
+               {
+                       //this code is run before every call to IConsoleAction.Run() by ConsoleApp, 
+                       //uncomment it to see that happening
+                       //System.Console.WriteLine("Hi there, something's about to happen!");
+               }
        ]]></x:Code>
 </ConsoleApp>