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)
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)
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))
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 ||
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";
+ }
+ }
}
}
}
}
+
+ [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");
+ }
+ }
}
}
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 ()
{
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<EventStore xmlns="clr-namespace:MonoTests.System.Xaml;assembly=System.Xaml_test_net_4_0">
+ <EventStore.Event1>Method3</EventStore.Event1>
+</EventStore>
--- /dev/null
+<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>