Add support for DependencyPropertyChangedEventHandler to EventAction

This commit is contained in:
Antony Male 2015-02-24 15:37:28 +00:00
parent 9a5143c343
commit 51007f4a22
2 changed files with 69 additions and 7 deletions

View File

@ -14,7 +14,11 @@ namespace Stylet.Xaml
public class EventAction : ActionBase
{
private static readonly ILogger logger = LogManager.GetLogger(typeof(EventAction));
private static readonly MethodInfo invokeCommandMethodInfo = typeof(EventAction).GetMethod("InvokeCommand", BindingFlags.NonPublic | BindingFlags.Instance);
private static readonly MethodInfo[] invokeCommandMethodInfos = new[]
{
typeof(EventAction).GetMethod("InvokeEventArgsCommand", BindingFlags.NonPublic | BindingFlags.Instance),
typeof(EventAction).GetMethod("InvokeDependencyCommand", BindingFlags.NonPublic | BindingFlags.Instance),
};
/// <summary>
/// Type of event handler
@ -49,8 +53,8 @@ namespace Stylet.Xaml
{
var methodParameters = targetMethodInfo.GetParameters();
if (!(methodParameters.Length == 0 ||
(methodParameters.Length == 1 && typeof(EventArgs).IsAssignableFrom(methodParameters[0].ParameterType)) ||
(methodParameters.Length == 2 && typeof(EventArgs).IsAssignableFrom(methodParameters[1].ParameterType))))
(methodParameters.Length == 1 && (typeof(EventArgs).IsAssignableFrom(methodParameters[0].ParameterType) || methodParameters[0].ParameterType == typeof(DependencyPropertyChangedEventArgs))) ||
(methodParameters.Length == 2 && (typeof(EventArgs).IsAssignableFrom(methodParameters[1].ParameterType) || methodParameters[1].ParameterType == typeof(DependencyPropertyChangedEventArgs)))))
{
var e = new ActionSignatureInvalidException(String.Format("Method {0} on {1} must have the signatures void Method(), void Method(EventArgsOrSubClass e), or void Method(object sender, EventArgsOrSubClass e)", this.MethodName, newTargetType.Name));
logger.Error(e);
@ -64,18 +68,40 @@ namespace Stylet.Xaml
/// <returns>An event hander, which, when invoked, will invoke the action</returns>
public Delegate GetDelegate()
{
var del = Delegate.CreateDelegate(this.eventHandlerType, this, invokeCommandMethodInfo, false);
Delegate del = null;
foreach (var invokeCommandMethodInfo in invokeCommandMethodInfos)
{
del = Delegate.CreateDelegate(this.eventHandlerType, this, invokeCommandMethodInfo, false);
if (del != null)
break;
}
if (del == null)
{
var e = new ActionEventSignatureInvalidException(String.Format("Event being bound to does not have the '(object sender, EventArgsOrSubclass e)' signature we were expecting. Method {0} on target {1}", this.MethodName, this.Target));
var msg = String.Format("Event being bound to does not have a signature we know about. Method {0} on target {1}. Valid signatures are:" +
"Valid signatures are:\n" +
" - '(object sender, EventArgsOrSubclass e)'\n" +
" - '(object sender, DependencyPropertyChangedEventArgs e)'", this.MethodName, this.Target);
var e = new ActionEventSignatureInvalidException(msg);
logger.Error(e);
throw e;
}
return del;
}
private void InvokeDependencyCommand(object sender, DependencyPropertyChangedEventArgs e)
{
this.InvokeCommand(sender, e);
}
private void InvokeEventArgsCommand(object sender, EventArgs e)
{
this.InvokeCommand(sender, e);
}
// ReSharper disable once UnusedMember.Local
private void InvokeCommand(object sender, EventArgs e)
private void InvokeCommand(object sender, object e)
{
// If we've made it this far and the target is still the default, then something's wrong
// Make sure they know
@ -83,7 +109,7 @@ namespace Stylet.Xaml
{
var ex = new ActionNotSetException(String.Format("View.ActionTarget not on control {0} (method {1}). " +
"This probably means the control hasn't inherited it from a parent, e.g. because a ContextMenu or Popup sits in the visual tree. " +
"You will need so set 's:View.ActionTarget' explicitly. See the wiki for more details.", this.Subject, this.MethodName));
"You will need so set 's:View.ActionTarget' explicitly. See the wiki section \"Actions\" for more details.", this.Subject, this.MethodName));
logger.Error(ex);
throw ex;
}

View File

@ -21,6 +21,7 @@ namespace StyletUnitTests
#pragma warning disable 0067
public event EventHandler SimpleEventHandler;
public event Action BadEventHandler;
public event DependencyPropertyChangedEventHandler DependencyChangedEventHandler;
#pragma warning restore 0067
}
@ -57,6 +58,18 @@ namespace StyletUnitTests
this.EventArgs = e;
}
public DependencyPropertyChangedEventArgs DependencyChangedEventArgs;
public void DoSomethingWithDependencyChangedEventArgs(DependencyPropertyChangedEventArgs e)
{
this.DependencyChangedEventArgs = e;
}
public void DoSomethingWithObjectAndDependencyChangedEventArgs(object sender, DependencyPropertyChangedEventArgs e)
{
this.Sender = sender;
this.DependencyChangedEventArgs = e;
}
public void DoSomethingUnsuccessfully()
{
throw new InvalidOperationException("foo");
@ -70,6 +83,7 @@ namespace StyletUnitTests
private DependencyObject subject;
private Target target;
private EventInfo eventInfo;
private EventInfo dependencyChangedEventInfo;
[SetUp]
public void SetUp()
@ -77,6 +91,7 @@ namespace StyletUnitTests
this.target = new Target();
this.subject = new Subject();
this.eventInfo = typeof(Subject).GetEvent("SimpleEventHandler");
this.dependencyChangedEventInfo = typeof(Subject).GetEvent("DependencyChangedEventHandler");
View.SetActionTarget(this.subject, this.target);
}
@ -175,6 +190,27 @@ namespace StyletUnitTests
Assert.AreEqual(arg, this.target.EventArgs);
}
[Test]
public void InvokingCommandCallsMethodWithDependencyChangedEventArgs()
{
var cmd = new EventAction(this.subject, this.dependencyChangedEventInfo.EventHandlerType, "DoSomethingWithDependencyChangedEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var arg = new DependencyPropertyChangedEventArgs();
cmd.GetDelegate().DynamicInvoke(null, arg);
Assert.AreEqual(arg, this.target.DependencyChangedEventArgs);
}
[Test]
public void InvokingCommandCallsMethodWithSenderAndDependencyChangedEventArgs()
{
var cmd = new EventAction(this.subject, this.dependencyChangedEventInfo.EventHandlerType, "DoSomethingWithObjectAndDependencyChangedEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var sender = new object();
var arg = new DependencyPropertyChangedEventArgs();
cmd.GetDelegate().DynamicInvoke(sender, arg);
Assert.AreEqual(sender, this.target.Sender);
Assert.AreEqual(arg, this.target.DependencyChangedEventArgs);
}
[Test]
public void BadEventHandlerSignatureThrows()
{