Implemented event support.
authorAtsushi Eno <atsushi@ximian.com>
Thu, 13 Jan 2011 12:12:41 +0000 (21:12 +0900)
committerAtsushi Eno <atsushi@ximian.com>
Thu, 13 Jan 2011 12:12:41 +0000 (21:12 +0900)
mcs/class/System.Xaml/System.Xaml/XamlObjectWriter.cs
mcs/class/System.Xaml/Test/System.Xaml/TestedTypes.cs
mcs/class/System.Xaml/Test/System.Xaml/XamlObjectWriterTest.cs
mcs/class/System.Xaml/Test/System.Xaml/XamlXmlReaderTest.cs
mcs/class/System.Xaml/Test/XmlFiles/EventStore.xml [new file with mode: 0644]
mcs/class/System.Xaml/Test/XmlFiles/EventStore2.xml [new file with mode: 0644]
mcs/class/System.Xaml/Test/XmlFiles/EventStore3.xml [new file with mode: 0644]
mcs/class/System.Xaml/Test/XmlFiles/EventStore4.xml [new file with mode: 0644]

index 71c42d390060e5ee2fc62423bb8fb804237d7f15..c47440934cab26af31ab33789ef95d4f649ca79b 100644 (file)
@@ -323,11 +323,36 @@ namespace System.Xaml
                                string name = (string) CurrentMemberState.Value;
                                name_scope.RegisterName (name, state.Value);
                        } else {
-                               if (!xm.IsReadOnly) // exclude read-only object such as collection item.
+                               if (xm.IsEvent)
+                                       SetEvent (xm, (string) CurrentMemberState.Value);
+                               else if (!xm.IsReadOnly) // exclude read-only object such as collection item.
                                        SetValue (xm, CurrentMemberState.Value);
                        }
                }
 
+               void SetEvent (XamlMember member, string value)
+               {
+                       if (member.UnderlyingMember == null)
+                               throw new XamlObjectWriterException (String.Format ("Event {0} has no underlying member to attach event", member));
+
+                       int idx = value.LastIndexOf ('.');
+                       var xt = idx < 0 ? member.DeclaringType : ResolveTypeFromName (value.Substring (0, idx));
+                       if (xt == null)
+                               throw new XamlObjectWriterException (String.Format ("Referenced type {0} in event {1} was not found", value, member));
+                       if (xt.UnderlyingType == null)
+                               throw new XamlObjectWriterException (String.Format ("Referenced type {0} in event {1} has no underlying type", value, member));
+                       string mn = idx < 0 ? value : value.Substring (idx + 1);
+                       var ev = (EventInfo) member.UnderlyingMember;
+                       // get an appropriate MethodInfo overload whose signature matches the event's handler type.
+                       // FIXME: this may need more strict match. RuntimeBinder may be useful here.
+                       var eventMethodParams = ev.EventHandlerType.GetMethod ("Invoke").GetParameters ();
+                       var mi = xt.UnderlyingType.GetMethod (mn, (from pi in eventMethodParams select pi.ParameterType).ToArray ());
+                       if (mi == null)
+                               throw new XamlObjectWriterException (String.Format ("Referenced value method {0} in type {1} indicated by event {2} was not found", mn, value, member));
+                       var obj = object_states.Peek ().Value;
+                       ev.AddEventHandler (obj, Delegate.CreateDelegate (ev.EventHandlerType, obj, mi));
+               }
+
                void SetValue (XamlMember member, object value)
                {
                        if (member == XamlLanguage.FactoryMethod)
@@ -377,8 +402,10 @@ namespace System.Xaml
                                if (xm == XamlLanguage.Initialization) {
                                        state.Value = GetCorrectlyTypedValue (xt, obj);
                                        state.IsInstantiated = true;
-                               }
-                               else if (xm.Type.IsXData) {
+                               } else if (xm.IsEvent) {
+                                       ms.Value = (string) obj; // save name of value delegate (method).
+                                       state.IsInstantiated = true;
+                               } else if (xm.Type.IsXData) {
                                        var xdata = (XData) obj;
                                        var ixser = xm.Invoker.GetValue (state.Value) as IXmlSerializable;
                                        if (ixser != null)
@@ -448,10 +475,8 @@ namespace System.Xaml
                                return value;
 
                        // FIXME: this could be generalized by some means, but I cannot find any.
-                       if (xt.UnderlyingType == typeof (XamlType) && value is string) {
-                               var nsr = (IXamlNamespaceResolver) service_provider.GetService (typeof (IXamlNamespaceResolver));
-                               value = sctx.GetXamlType (XamlTypeName.Parse ((string) value, nsr));
-                       }
+                       if (xt.UnderlyingType == typeof (XamlType) && value is string)
+                               value = ResolveTypeFromName ((string) value);
 
                        // FIXME: this could be generalized by some means, but I cannot find any.
                        if (xt.UnderlyingType == typeof (Type))
@@ -472,6 +497,12 @@ namespace System.Xaml
                        throw new XamlObjectWriterException (String.Format ("Value '{1}' (of type {2}) is not of or convertible to type {0}", xt, value, value != null ? (object) value.GetType () : "(null)"));
                }
 
+               XamlType ResolveTypeFromName (string name)
+               {
+                       var nsr = (IXamlNamespaceResolver) service_provider.GetService (typeof (IXamlNamespaceResolver));
+                       return sctx.GetXamlType (XamlTypeName.Parse (name, nsr));
+               }
+
                bool IsAllowedType (XamlType xt, object value)
                {
                        return  xt == null ||
index ec0818d56c6054ede4ce652177f4aed55c775ed3..70835db45ea59e51410a8abcf0387848e45236ed 100755 (executable)
@@ -732,4 +732,75 @@ namespace MonoTests.System.Xaml
        public class Attached : Attachable
        {
        }
+
+       public class EventStore
+       {
+               public bool Method1Invoked;
+
+               public event EventHandler<EventArgs> Event1;
+               public event Func<object> Event2;
+
+               public object Examine ()
+               {
+                       if (Event1 != null)
+                               Event1 (this, EventArgs.Empty);
+                       if (Event2 != null)
+                               return Event2 ();
+                       else
+                               return null;
+               }
+
+               public void Method1 ()
+               {
+                       throw new Exception ();
+               }
+
+               public void Method1 (object o, EventArgs e)
+               {
+                       Method1Invoked = true;
+               }
+
+               public object Method2 ()
+               {
+                       return "foo";
+               }
+       }
+
+       public class EventStore2<TEventArgs> where TEventArgs : EventArgs
+       {
+               public bool Method1Invoked;
+
+               public event EventHandler<TEventArgs> Event1;
+               public event Func<object> Event2;
+
+               public object Examine ()
+               {
+                       if (Event1 != null)
+                               Event1 (this, default (TEventArgs));
+                       if (Event2 != null)
+                               return Event2 ();
+                       else
+                               return null;
+               }
+
+               public void Method1 ()
+               {
+                       throw new Exception ();
+               }
+
+               public void Method1 (object o, EventArgs e)
+               {
+                       throw new Exception ();
+               }
+
+               public void Method1 (object o, TEventArgs e)
+               {
+                       Method1Invoked = true;
+               }
+
+               public object Method2 ()
+               {
+                       return "foo";
+               }
+       }
 }
index a5e833fd4dea60d8009e4aa2f8d6a1e34258d7a1..69fafe3f08c2c50417b76e3925c13ff7f48803ce 100755 (executable)
@@ -1225,5 +1225,44 @@ namespace MonoTests.System.Xaml
                                }
                        }
                }
+
+               [Test]
+               public void Write_EventStore ()
+               {
+                       using (var xr = GetReader ("EventStore.xml")) {
+                               var res = (EventStore) XamlServices.Load (xr);
+                               Assert.AreEqual ("foo", res.Examine (), "#1");
+                               Assert.IsTrue (res.Method1Invoked, "#2");
+                       }
+               }
+
+               [Test]
+               [ExpectedException (typeof (XamlDuplicateMemberException))] // for two occurence of Event1 ...
+               public void Write_EventStore2 ()
+               {
+                       using (var xr = GetReader ("EventStore2.xml")) {
+                               XamlServices.Load (xr);
+                       }
+               }
+
+               [Test]
+               [ExpectedException (typeof (XamlObjectWriterException))] // attaching nonexistent method
+               public void Write_EventStore3 ()
+               {
+                       using (var xr = GetReader ("EventStore3.xml")) {
+                               XamlServices.Load (xr);
+                       }
+               }
+
+               [Test]
+               [Category ("NotWorking")] // type resolution failure.
+               public void Write_EventStore4 ()
+               {
+                       using (var xr = GetReader ("EventStore4.xml")) {
+                               var res = (EventStore2<EventArgs>) XamlServices.Load (xr);
+                               Assert.AreEqual ("foo", res.Examine (), "#1");
+                               Assert.IsTrue (res.Method1Invoked, "#2");
+                       }
+               }
        }
 }
index 806bf49a2c00cd98203c2b18e3c01b043a2a164e..b8353813e853ecd830c9860c19a48603f3fc7ddf 100755 (executable)
@@ -243,6 +243,64 @@ namespace MonoTests.System.Xaml
                        Assert.IsFalse (r.Read (), "end");
                }
 
+               [Test]
+               public void ReadEventStore ()
+               {
+                       var r = GetReader ("EventStore2.xml");
+
+                       var xt = r.SchemaContext.GetXamlType (typeof (EventStore));
+                       var xm = xt.GetMember ("Event1");
+                       Assert.IsNotNull (xt, "premise#1");
+                       Assert.IsNotNull (xm, "premise#2");
+                       Assert.IsTrue (xm.IsEvent, "premise#3");
+                       while (true) {
+                               r.Read ();
+                               if (r.Member != null && r.Member.IsEvent)
+                                       break;
+                               if (r.IsEof)
+                                       Assert.Fail ("Items did not appear");
+                       }
+
+                       Assert.AreEqual (xm, r.Member, "#x1");
+                       Assert.AreEqual ("Event1", r.Member.Name, "#x2");
+
+                       Assert.IsTrue (r.Read (), "#x11");
+                       Assert.AreEqual (XamlNodeType.Value, r.NodeType, "#x12");
+                       Assert.AreEqual ("Method1", r.Value, "#x13");
+
+                       Assert.IsTrue (r.Read (), "#x21");
+                       Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "#x22");
+
+                       xm = xt.GetMember ("Event2");
+                       Assert.IsTrue (r.Read (), "#x31");
+                       Assert.AreEqual (xm, r.Member, "#x32");
+                       Assert.AreEqual ("Event2", r.Member.Name, "#x33");
+
+                       Assert.IsTrue (r.Read (), "#x41");
+                       Assert.AreEqual (XamlNodeType.Value, r.NodeType, "#x42");
+                       Assert.AreEqual ("Method2", r.Value, "#x43");
+
+                       Assert.IsTrue (r.Read (), "#x51");
+                       Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "#x52");
+
+                       Assert.IsTrue (r.Read (), "#x61");
+                       Assert.AreEqual ("Event1", r.Member.Name, "#x62");
+
+                       Assert.IsTrue (r.Read (), "#x71");
+                       Assert.AreEqual (XamlNodeType.Value, r.NodeType, "#x72");
+                       Assert.AreEqual ("Method3", r.Value, "#x73"); // nonexistent, but no need to raise an error.
+
+                       Assert.IsTrue (r.Read (), "#x81");
+                       Assert.AreEqual (XamlNodeType.EndMember, r.NodeType, "#x82");
+
+                       while (!r.IsEof)
+                               r.Read ();
+
+                       r.Close ();
+               }
+
+               // common XamlReader tests.
+
                [Test]
                public void Read_String ()
                {
diff --git a/mcs/class/System.Xaml/Test/XmlFiles/EventStore.xml b/mcs/class/System.Xaml/Test/XmlFiles/EventStore.xml
new file mode 100644 (file)
index 0000000..2e58178
--- /dev/null
@@ -0,0 +1,4 @@
+<EventStore xmlns="clr-namespace:MonoTests.System.Xaml;assembly=System.Xaml_test_net_4_0">
+  <EventStore.Event1>Method1</EventStore.Event1>
+  <EventStore.Event2>Method2</EventStore.Event2>
+</EventStore>
diff --git a/mcs/class/System.Xaml/Test/XmlFiles/EventStore2.xml b/mcs/class/System.Xaml/Test/XmlFiles/EventStore2.xml
new file mode 100644 (file)
index 0000000..b84d080
--- /dev/null
@@ -0,0 +1,5 @@
+<EventStore xmlns="clr-namespace:MonoTests.System.Xaml;assembly=System.Xaml_test_net_4_0">
+  <EventStore.Event1>Method1</EventStore.Event1>
+  <EventStore.Event2>Method2</EventStore.Event2>
+  <EventStore.Event1>Method3</EventStore.Event1>
+</EventStore>
diff --git a/mcs/class/System.Xaml/Test/XmlFiles/EventStore3.xml b/mcs/class/System.Xaml/Test/XmlFiles/EventStore3.xml
new file mode 100644 (file)
index 0000000..89a2cb3
--- /dev/null
@@ -0,0 +1,3 @@
+<EventStore xmlns="clr-namespace:MonoTests.System.Xaml;assembly=System.Xaml_test_net_4_0">
+  <EventStore.Event1>Method3</EventStore.Event1>
+</EventStore>
diff --git a/mcs/class/System.Xaml/Test/XmlFiles/EventStore4.xml b/mcs/class/System.Xaml/Test/XmlFiles/EventStore4.xml
new file mode 100644 (file)
index 0000000..71afc8b
--- /dev/null
@@ -0,0 +1,4 @@
+<EventStore2 xmlns="clr-namespace:MonoTests.System.Xaml;assembly=System.Xaml_test_net_4_0" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" x:TypeArguments="s:EventArgs">
+  <EventStore2.Event1>Method1</EventStore2.Event1>
+  <EventStore2.Event2>Method2</EventStore2.Event2>
+</EventStore2>