Implement another mechanism of backup ActionTarget, using IRootObjectProvider

This commit is contained in:
Antony Male 2015-10-06 12:49:22 +01:00
parent 54cd9cf18f
commit fdfaefa94e
7 changed files with 132 additions and 68 deletions

View File

@ -4,6 +4,8 @@ using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Windows;
using System.Windows.Data;
using System.Globalization;
using System.Diagnostics;
namespace Stylet.Xaml
{
@ -57,11 +59,12 @@ namespace Stylet.Xaml
/// Initialises a new instance of the <see cref="ActionBase"/> class
/// </summary>
/// <param name="subject">View to grab the View.ActionTarget from</param>
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
/// <param name="methodName">Method name. the MyMethod in Buttom Command="{s:Action MyMethod}".</param>
/// <param name="targetNullBehaviour">Behaviour for it the relevant View.ActionTarget is null</param>
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
/// <param name="logger">Logger to use</param>
public ActionBase(DependencyObject subject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour, ILogger logger)
public ActionBase(DependencyObject subject, DependencyObject backupSubject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour, ILogger logger)
{
this.Subject = subject;
this.MethodName = methodName;
@ -69,13 +72,30 @@ namespace Stylet.Xaml
this.ActionNonExistentBehaviour = actionNonExistentBehaviour;
this.logger = logger;
var binding = new Binding()
var actionTargetBinding = new Binding()
{
Path = new PropertyPath(View.ActionTargetProperty),
Mode = BindingMode.OneWay,
Source = this.Subject,
};
BindingOperations.SetBinding(this, targetProperty, binding);
if (backupSubject == null)
{
BindingOperations.SetBinding(this, targetProperty, actionTargetBinding);
}
else
{
var multiBinding = new MultiBinding();
multiBinding.Converter = new MultiBindingToActionTargetConverter();
multiBinding.Bindings.Add(actionTargetBinding);
multiBinding.Bindings.Add(new Binding()
{
Path = new PropertyPath(View.ActionTargetProperty),
Mode = BindingMode.OneWay,
Source = backupSubject,
});
BindingOperations.SetBinding(this, targetProperty, multiBinding);
}
}
private void UpdateActionTarget(object oldTarget, object newTarget)
@ -178,5 +198,26 @@ namespace Stylet.Xaml
ExceptionDispatchInfo.Capture(e.InnerException).Throw();
}
}
private class MultiBindingToActionTargetConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Debug.Assert(values.Length == 2);
if (values[0] != View.InitialActionTarget)
return values[0];
if (values[1] != View.InitialActionTarget)
return values[1];
return View.InitialActionTarget;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
}
}

View File

@ -3,6 +3,7 @@ using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Xaml;
namespace Stylet.Xaml
{
@ -106,17 +107,22 @@ namespace Stylet.Xaml
if (!(valueService.TargetObject is DependencyObject))
return this;
var targetObject = (DependencyObject)valueService.TargetObject;
var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
var rootObject = rootObjectProvider == null ? null : rootObjectProvider.RootObject as DependencyObject;
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
if (propertyAsDependencyProperty != null && propertyAsDependencyProperty.PropertyType == typeof(ICommand))
{
// If they're in design mode and haven't set View.ActionTarget, default to looking sensible
return new CommandAction((DependencyObject)valueService.TargetObject, this.Method, this.CommandNullTargetBehaviour, this.CommandActionNotFoundBehaviour);
return new CommandAction(targetObject, rootObject, this.Method, this.CommandNullTargetBehaviour, this.CommandActionNotFoundBehaviour);
}
var propertyAsEventInfo = valueService.TargetProperty as EventInfo;
if (propertyAsEventInfo != null)
{
var ec = new EventAction((DependencyObject)valueService.TargetObject, propertyAsEventInfo.EventHandlerType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
var ec = new EventAction(targetObject, rootObject, propertyAsEventInfo.EventHandlerType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
return ec.GetDelegate();
}
@ -127,7 +133,7 @@ namespace Stylet.Xaml
var parameters = propertyAsMethodInfo.GetParameters();
if (parameters.Length == 2 && typeof(Delegate).IsAssignableFrom(parameters[1].ParameterType))
{
var ec = new EventAction((DependencyObject)valueService.TargetObject, parameters[1].ParameterType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
var ec = new EventAction(targetObject, rootObject, parameters[1].ParameterType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
return ec.GetDelegate();
}
}

View File

@ -29,11 +29,12 @@ namespace Stylet.Xaml
/// Initialises a new instance of the <see cref="CommandAction"/> class
/// </summary>
/// <param name="subject">View to grab the View.ActionTarget from</param>
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
/// <param name="methodName">Method name. the MyMethod in Buttom Command="{s:Action MyMethod}".</param>
/// <param name="targetNullBehaviour">Behaviour for it the relevant View.ActionTarget is null</param>
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
public CommandAction(DependencyObject subject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
: base(subject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
public CommandAction(DependencyObject subject, DependencyObject backupSubject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
: base(subject, backupSubject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
{ }
private string GuardName

View File

@ -26,12 +26,13 @@ namespace Stylet.Xaml
/// Initialises a new instance of the <see cref="EventAction"/> class
/// </summary>
/// <param name="subject">View whose View.ActionTarget we watch</param>
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
/// <param name="eventHandlerType">Type of event handler we're returning a delegate for</param>
/// <param name="methodName">The MyMethod in {s:Action MyMethod}, this is what we call when the event's fired</param>
/// <param name="targetNullBehaviour">Behaviour for it the relevant View.ActionTarget is null</param>
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
public EventAction(DependencyObject subject, Type eventHandlerType, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
: base(subject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
public EventAction(DependencyObject subject, DependencyObject backupSubject, Type eventHandlerType, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
: base(subject, backupSubject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
{
if (targetNullBehaviour == ActionUnavailableBehaviour.Disable)
throw new ArgumentException("Setting NullTarget = Disable is unsupported when used on an Event");

View File

@ -12,12 +12,9 @@ namespace StyletIntegrationTests
{
private readonly IWindowManager windowManager;
public ChildViewModel ChildViewModel { get; private set; }
public ShellViewModel(IWindowManager windowManager)
{
this.windowManager = windowManager;
this.ChildViewModel = new ChildViewModel(windowManager);
this.DisplayName = "ShellViewModel";
}
@ -68,18 +65,8 @@ namespace StyletIntegrationTests
else
this.windowManager.ShowMessageBox("Failure");
}
}
public class ChildViewModel
{
private readonly IWindowManager windowManager;
public ChildViewModel(IWindowManager windowManager)
{
this.windowManager = windowManager;
}
public void Foo()
public void ShowActionTargetSaved()
{
this.windowManager.ShowMessageBox("Success!");
}

View File

@ -76,14 +76,14 @@ namespace StyletUnitTests
[Test]
public void ThrowsIfTargetNullBehaviourIsThrowAndTargetBecomesNull()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Disable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Disable);
Assert.Throws<ActionTargetNullException>(() => View.SetActionTarget(this.subject, null));
}
[Test]
public void DisablesIfTargetNullBehaviourIsDisableAndTargetIsNull()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Disable, ActionUnavailableBehaviour.Disable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Disable, ActionUnavailableBehaviour.Disable);
View.SetActionTarget(this.subject, null);
Assert.False(cmd.CanExecute(null));
}
@ -91,7 +91,7 @@ namespace StyletUnitTests
[Test]
public void EnablesIfTargetNullBehaviourIsEnableAndTargetIsNull()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Disable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Disable);
View.SetActionTarget(this.subject, null);
Assert.True(cmd.CanExecute(null));
}
@ -99,7 +99,7 @@ namespace StyletUnitTests
[Test]
public void ThrowsIfActionNonExistentBehaviourIsThrowAndActionIsNonExistent()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.DoesNotThrow(() => View.SetActionTarget(this.subject, new Target2()));
Assert.Throws<ActionNotFoundException>(() => cmd.Execute(null));
}
@ -107,7 +107,7 @@ namespace StyletUnitTests
[Test]
public void DisablesIfActionNonExistentBehaviourIsThrowAndActionIsNonExistent()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Disable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Disable);
View.SetActionTarget(this.subject, new Target2());
Assert.False(cmd.CanExecute(null));
}
@ -115,7 +115,7 @@ namespace StyletUnitTests
[Test]
public void EnablesIfActionNonExistentBehaviourIsThrowAndActionIsNonExistent()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Enable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Enable);
View.SetActionTarget(this.subject, new Target2());
Assert.True(cmd.CanExecute(null));
}
@ -123,7 +123,7 @@ namespace StyletUnitTests
[Test]
public void EnablesIfTargetAndActionExistAndNoGuardMethod()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.True(cmd.CanExecute(null));
}
@ -131,7 +131,7 @@ namespace StyletUnitTests
public void EnablesIfTargetAndActionExistAndGuardMethodReturnsTrue()
{
this.target.CanDoSomethingWithGuard = true;
var cmd = new CommandAction(this.subject, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.True(cmd.CanExecute(null));
}
@ -139,14 +139,14 @@ namespace StyletUnitTests
public void DisablesIfTargetAndActionExistAndGuardMethodReturnsFalse()
{
this.target.CanDoSomethingWithGuard = false;
var cmd = new CommandAction(this.subject, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.False(cmd.CanExecute(null));
}
[Test]
public void IgnoresGuardIfGuardDoesNotReturnBool()
{
var cmd = new CommandAction(this.subject, "DoSomethingWithBadGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithBadGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.True(cmd.CanExecute(true));
}
@ -154,7 +154,7 @@ namespace StyletUnitTests
public void ChangesEnabledStateWhenGuardChanges()
{
this.target.CanDoSomethingWithGuard = false;
var cmd = new CommandAction(this.subject, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.False(cmd.CanExecute(null));
this.target.CanDoSomethingWithGuard = true;
Assert.True(cmd.CanExecute(null));
@ -164,7 +164,7 @@ namespace StyletUnitTests
public void RaisesEventWhenGuardValueChanges()
{
this.target.CanDoSomethingWithGuard = false;
var cmd = new CommandAction(this.subject, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
bool eventRaised = false;
cmd.CanExecuteChanged += (o, e) => eventRaised = true;
this.target.CanDoSomethingWithGuard = true;
@ -174,7 +174,7 @@ namespace StyletUnitTests
[Test]
public void RaisesEventWhenTargetChanges()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Disable, ActionUnavailableBehaviour.Disable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Disable, ActionUnavailableBehaviour.Disable);
bool eventRaised = false;
cmd.CanExecuteChanged += (o, e) => eventRaised = true;
View.SetActionTarget(this.subject, null);
@ -184,7 +184,7 @@ namespace StyletUnitTests
[Test]
public void ExecuteDoesNothingIfTargetIsNull()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
View.SetActionTarget(this.subject, null);
Assert.DoesNotThrow(() => cmd.Execute(null));
}
@ -192,7 +192,7 @@ namespace StyletUnitTests
[Test]
public void ExecuteDoesNothingIfActionIsNull()
{
var cmd = new CommandAction(this.subject, "DoesNotExist", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new CommandAction(this.subject, null, "DoesNotExist", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
View.SetActionTarget(this.subject, null);
Assert.DoesNotThrow(() => cmd.Execute(null));
}
@ -200,7 +200,7 @@ namespace StyletUnitTests
[Test]
public void ExecuteCallsMethod()
{
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
cmd.Execute(null);
Assert.True(this.target.DoSomethingCalled);
}
@ -208,7 +208,7 @@ namespace StyletUnitTests
[Test]
public void ExecutePassesArgumentIfGiven()
{
var cmd = new CommandAction(this.subject, "DoSomethingWithArgument", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithArgument", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var arg = "hello";
cmd.Execute(arg);
Assert.AreEqual("hello", this.target.DoSomethingArgument);
@ -217,13 +217,13 @@ namespace StyletUnitTests
[Test]
public void ThrowsIfMethodHasMoreThanOneParameter()
{
Assert.Throws<ActionSignatureInvalidException>(() => new CommandAction(this.subject, "DoSomethingWithManyArguments", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
Assert.Throws<ActionSignatureInvalidException>(() => new CommandAction(this.subject, null, "DoSomethingWithManyArguments", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
}
[Test]
public void PropagatesActionException()
{
var cmd = new CommandAction(this.subject, "DoSomethingUnsuccessfully", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new CommandAction(this.subject, null, "DoSomethingUnsuccessfully", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var e = Assert.Throws<InvalidOperationException>(() => cmd.Execute(null));
Assert.AreEqual("woo", e.Message);
}
@ -231,7 +231,7 @@ namespace StyletUnitTests
[Test]
public void PropagatesGuardPropertException()
{
var cmd = new CommandAction(this.subject, "DoSomethingWithUnsuccessfulGuardMethod", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomethingWithUnsuccessfulGuardMethod", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var e = Assert.Throws<InvalidOperationException>(() => cmd.CanExecute(null));
Assert.AreEqual("foo", e.Message);
}
@ -240,7 +240,7 @@ namespace StyletUnitTests
public void ControlIsEnabledIfTargetIsDefault()
{
View.SetActionTarget(this.subject, View.InitialActionTarget);
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.True(cmd.CanExecute(null));
}
@ -248,7 +248,7 @@ namespace StyletUnitTests
public void ExecuteThrowsIfTargetIsDefault()
{
View.SetActionTarget(this.subject, View.InitialActionTarget);
var cmd = new CommandAction(this.subject, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
Assert.Throws<ActionNotSetException>(() => cmd.Execute(null));
}
@ -258,7 +258,7 @@ namespace StyletUnitTests
var view = new DependencyObject();
var weakView = new WeakReference(view);
View.SetActionTarget(view, this.target);
var cmd = new CommandAction(view, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(view, null, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
view = null;
cmd = null;
@ -272,7 +272,7 @@ namespace StyletUnitTests
public void OperatesAfterCollection()
{
var view = new DependencyObject();
var cmd = new CommandAction(view, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new CommandAction(view, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
GC.Collect();
@ -281,5 +281,19 @@ namespace StyletUnitTests
cmd.Execute(null);
Assert.IsTrue(this.target.DoSomethingCalled);
}
[Test]
public void UsesDataContextIfActionTargetNotAvailable()
{
var view = new DependencyObject();
var backupView = new DependencyObject();
var cmd = new CommandAction(backupView, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
View.SetActionTarget(backupView, this.target);
view.SetValue(FrameworkElement.DataContextProperty, this.target);
cmd.Execute(null);
Assert.IsTrue(this.target.DoSomethingCalled);
}
}
}

View File

@ -92,26 +92,26 @@ namespace StyletUnitTests
[Test]
public void ThrowsIfNullTargetBehaviourIsDisable()
{
Assert.Throws<ArgumentException>(() => new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Disable, ActionUnavailableBehaviour.Enable));
Assert.Throws<ArgumentException>(() => new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Disable, ActionUnavailableBehaviour.Enable));
}
[Test]
public void ThrowsIfNonExistentActionBehaviourIsDisable()
{
Assert.Throws<ArgumentException>(() => new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Disable));
Assert.Throws<ArgumentException>(() => new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Disable));
}
[Test]
public void ThrowsIfTargetNullBehaviourIsThrowAndTargetBecomesNull()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Enable);
Assert.Throws<ActionTargetNullException>(() => View.SetActionTarget(this.subject, null));
}
[Test]
public void ThrowsWhenClickedIfActionNonExistentBehaviourIsThrowAndActionIsNonExistent()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Throw);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Throw);
Assert.DoesNotThrow(() => View.SetActionTarget(this.subject, new Target2()));
var e = Assert.Throws<TargetInvocationException>(() => cmd.GetDelegate().DynamicInvoke(null, new RoutedEventArgs()));
Assert.IsInstanceOf<ActionNotFoundException>(e.InnerException);
@ -120,31 +120,31 @@ namespace StyletUnitTests
[Test]
public void ThrowsIfMethodHasTooManyArguments()
{
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingWithTooManyArguments", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingWithTooManyArguments", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
}
[Test]
public void ThrowsIfMethodHasBadParameter()
{
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingWithBadArgument", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingWithBadArgument", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
}
[Test]
public void ThrowsIfMethodHasBadEventArgsParameter()
{
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingWithSenderAndBadArgument", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingWithSenderAndBadArgument", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
}
[Test]
public void ThrowsIfMethodHasTooManyParameters()
{
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingWithTooManyArguments", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
Assert.Throws<ActionSignatureInvalidException>(() => new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingWithTooManyArguments", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable));
}
[Test]
public void InvokingCommandDoesNothingIfTargetIsNull()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
View.SetActionTarget(this.subject, null);
cmd.GetDelegate().DynamicInvoke(null, null);
}
@ -152,7 +152,7 @@ namespace StyletUnitTests
[Test]
public void InvokingCommandDoesNothingIfActionIsNonExistent()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
View.SetActionTarget(this.subject, new Target2());
cmd.GetDelegate().DynamicInvoke(null, null);
}
@ -160,7 +160,7 @@ namespace StyletUnitTests
[Test]
public void InvokingCommandCallsMethod()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
cmd.GetDelegate().DynamicInvoke(null, null);
Assert.True(this.target.DoSomethingCalled);
}
@ -168,7 +168,7 @@ namespace StyletUnitTests
[Test]
public void InvokingCommandCallsMethodWithEventArgs()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingWithEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingWithEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var arg = new RoutedEventArgs();
cmd.GetDelegate().DynamicInvoke(null, arg);
Assert.AreEqual(arg, this.target.EventArgs);
@ -177,7 +177,7 @@ namespace StyletUnitTests
[Test]
public void InvokingCommandCallsMethodWithSenderAndEventArgs()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingWithObjectAndEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingWithObjectAndEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var sender = new object();
var arg = new RoutedEventArgs();
cmd.GetDelegate().DynamicInvoke(sender, arg);
@ -189,7 +189,7 @@ namespace StyletUnitTests
[Test]
public void InvokingCommandCallsMethodWithDependencyChangedEventArgs()
{
var cmd = new EventAction(this.subject, this.dependencyChangedEventInfo.EventHandlerType, "DoSomethingWithDependencyChangedEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.dependencyChangedEventInfo.EventHandlerType, "DoSomethingWithDependencyChangedEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var arg = new DependencyPropertyChangedEventArgs();
cmd.GetDelegate().DynamicInvoke(null, arg);
Assert.AreEqual(arg, this.target.DependencyChangedEventArgs);
@ -198,7 +198,7 @@ namespace StyletUnitTests
[Test]
public void InvokingCommandCallsMethodWithSenderAndDependencyChangedEventArgs()
{
var cmd = new EventAction(this.subject, this.dependencyChangedEventInfo.EventHandlerType, "DoSomethingWithObjectAndDependencyChangedEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.dependencyChangedEventInfo.EventHandlerType, "DoSomethingWithObjectAndDependencyChangedEventArgs", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var sender = new object();
var arg = new DependencyPropertyChangedEventArgs();
cmd.GetDelegate().DynamicInvoke(sender, arg);
@ -210,14 +210,14 @@ namespace StyletUnitTests
[Test]
public void BadEventHandlerSignatureThrows()
{
var cmd = new EventAction(this.subject, typeof(Subject).GetEvent("BadEventHandler").EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, typeof(Subject).GetEvent("BadEventHandler").EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
Assert.Throws<ActionEventSignatureInvalidException>(() => cmd.GetDelegate());
}
[Test]
public void PropagatesActionException()
{
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomethingUnsuccessfully", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomethingUnsuccessfully", ActionUnavailableBehaviour.Enable, ActionUnavailableBehaviour.Enable);
var e = Assert.Throws<TargetInvocationException>(() => cmd.GetDelegate().DynamicInvoke(null, null));
Assert.IsInstanceOf<InvalidOperationException>(e.InnerException);
Assert.AreEqual("foo", e.InnerException.Message);
@ -227,7 +227,7 @@ namespace StyletUnitTests
public void ExecuteThrowsIfActionTargetIsDefault()
{
View.SetActionTarget(this.subject, View.InitialActionTarget);
var cmd = new EventAction(this.subject, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var e = Assert.Throws<TargetInvocationException>(() => cmd.GetDelegate().DynamicInvoke(null, null));
Assert.IsInstanceOf<ActionNotSetException>(e.InnerException);
}
@ -238,7 +238,7 @@ namespace StyletUnitTests
var view = new DependencyObject();
var weakView = new WeakReference(view);
View.SetActionTarget(view, this.target);
var cmd = new EventAction(view, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new EventAction(view, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
cmd = null;
view = null;
@ -251,7 +251,7 @@ namespace StyletUnitTests
public void OperatesAfterCollection()
{
var view = new DependencyObject();
var cmd = new EventAction(view, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
var cmd = new EventAction(view, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
GC.Collect();
@ -260,5 +260,19 @@ namespace StyletUnitTests
cmd.GetDelegate().DynamicInvoke(null, null);
Assert.IsTrue(this.target.DoSomethingCalled);
}
[Test]
public void UsesBackupSubjectIfActionTargetNotAvailable()
{
var view = new DependencyObject();
var backupView = new DependencyObject();
var cmd = new CommandAction(view, backupView, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
View.SetActionTarget(backupView, this.target);
view.SetValue(FrameworkElement.DataContextProperty, this.target);
cmd.Execute(null);
Assert.IsTrue(this.target.DoSomethingCalled);
}
}
}