mirror of https://github.com/AMT-Cheif/Stylet.git
Document CommandAction and EventAction, and make them consistent
This commit is contained in:
parent
7ee1f0ac0a
commit
92568e0cbf
|
@ -4,7 +4,7 @@
|
|||
xmlns:s="http://github.com/canton7/Stylet"
|
||||
Height="300" Width="300">
|
||||
<StackPanel>
|
||||
<TextBox Text="{Binding Name}"/>
|
||||
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Command="{s:Action SayHello}">Say Hello</Button>
|
||||
</StackPanel>
|
||||
</Window>
|
||||
|
|
|
@ -9,13 +9,22 @@ namespace Stylet.Samples.Hello
|
|||
{
|
||||
class ShellViewModel : Screen
|
||||
{
|
||||
public string Name { get; set; }
|
||||
private string _name;
|
||||
public string Name
|
||||
{
|
||||
get { return this._name; }
|
||||
set { SetAndNotify(ref this._name, value); this.NotifyOfPropertyChange(() => this.CanSayHello); }
|
||||
}
|
||||
|
||||
public ShellViewModel()
|
||||
{
|
||||
this.DisplayName = "Hello, Stylet";
|
||||
}
|
||||
|
||||
public bool CanSayHello
|
||||
{
|
||||
get { return !String.IsNullOrEmpty(this.Name); }
|
||||
}
|
||||
public void SayHello()
|
||||
{
|
||||
MessageBox.Show(String.Format("Hello, {0}", this.Name)); // Don't do this
|
||||
|
|
|
@ -30,13 +30,13 @@ namespace Stylet
|
|||
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
|
||||
if (propertyAsDependencyProperty != null && propertyAsDependencyProperty.PropertyType == typeof(ICommand))
|
||||
{
|
||||
return new ActionCommand((FrameworkElement)valueService.TargetObject, this.Method);
|
||||
return new CommandAction((FrameworkElement)valueService.TargetObject, this.Method);
|
||||
}
|
||||
|
||||
var propertyAsEventInfo = valueService.TargetProperty as EventInfo;
|
||||
if (propertyAsEventInfo != null)
|
||||
{
|
||||
var ec = new EventCommand((FrameworkElement)valueService.TargetObject, propertyAsEventInfo, this.Method);
|
||||
var ec = new EventAction((FrameworkElement)valueService.TargetObject, propertyAsEventInfo, this.Method);
|
||||
return ec.GetDelegate();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,23 +13,52 @@ using Expressions = System.Linq.Expressions;
|
|||
|
||||
namespace Stylet
|
||||
{
|
||||
public class ActionCommand : ICommand
|
||||
/// <summary>
|
||||
/// ICommand returned by ActionExtension for binding buttons, etc, to methods on a ViewModel.
|
||||
/// If the method has a parameter, CommandParameter is passed
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Watches the current View.ActionTarget, and looks for a method with the given name, calling it when the ICommand is called.
|
||||
/// If a bool property with name Get(methodName) exists, it will be observed and used to enable/disable the ICommand.
|
||||
/// </remarks>
|
||||
public class CommandAction : ICommand
|
||||
{
|
||||
/// <summary>
|
||||
/// View to grab the View.ActionTarget from
|
||||
/// </summary>
|
||||
private FrameworkElement subject;
|
||||
|
||||
/// <summary>
|
||||
/// Method name. E.g. if someone's gone Buttom Command="{s:Action MyMethod}", this is MyMethod.
|
||||
/// </summary>
|
||||
private string methodName;
|
||||
|
||||
/// <summary>
|
||||
/// Generated accessor to grab the value of the guard property, or null if there is none
|
||||
/// </summary>
|
||||
private Func<bool> guardPropertyGetter;
|
||||
|
||||
/// <summary>
|
||||
/// MethodInfo for the method to call. This has to exist, or we throw a wobbly
|
||||
/// </summary>
|
||||
private MethodInfo targetMethodInfo;
|
||||
|
||||
private object target;
|
||||
|
||||
public ActionCommand(FrameworkElement subject, string methodName)
|
||||
/// <summary>
|
||||
/// Create a new ActionCommand
|
||||
/// </summary>
|
||||
/// <param name="subject">View to grab the View.ActionTarget from</param>
|
||||
/// <param name="methodName">Method name. the MyMethod in Buttom Command="{s:Action MyMethod}".</param>
|
||||
public CommandAction(FrameworkElement subject, string methodName)
|
||||
{
|
||||
this.subject = subject;
|
||||
this.methodName = methodName;
|
||||
|
||||
this.UpdateGuardHandler();
|
||||
this.UpdateGuardAndMethod();
|
||||
|
||||
DependencyPropertyDescriptor.FromProperty(View.ActionTargetProperty, typeof(View)).AddValueChanged(this.subject, (o, e) => this.UpdateGuardHandler());
|
||||
// Observe the View.ActionTarget for changes, and re-bind the guard property and MethodInfo if it changes
|
||||
DependencyPropertyDescriptor.FromProperty(View.ActionTargetProperty, typeof(View)).AddValueChanged(this.subject, (o, e) => this.UpdateGuardAndMethod());
|
||||
}
|
||||
|
||||
private string GuardName
|
||||
|
@ -37,7 +66,7 @@ namespace Stylet
|
|||
get { return "Can" + this.methodName; }
|
||||
}
|
||||
|
||||
private void UpdateGuardHandler()
|
||||
private void UpdateGuardAndMethod()
|
||||
{
|
||||
var newTarget = View.GetActionTarget(this.subject);
|
||||
MethodInfo targetMethodInfo = null;
|
||||
|
@ -50,9 +79,9 @@ namespace Stylet
|
|||
var guardPropertyInfo = newTargetType.GetProperty(this.GuardName);
|
||||
if (guardPropertyInfo != null && guardPropertyInfo.PropertyType == typeof(bool))
|
||||
{
|
||||
var param = Expressions.Expression.Parameter(typeof(bool), "returnValue");
|
||||
var propertyAccess = Expressions.Expression.Property(param, guardPropertyInfo);
|
||||
this.guardPropertyGetter = Expressions.Expression.Lambda<Func<bool>>(propertyAccess, param).Compile();
|
||||
var targetExpression = Expressions.Expression.Constant(newTarget);
|
||||
var propertyAccess = Expressions.Expression.Property(targetExpression, guardPropertyInfo);
|
||||
this.guardPropertyGetter = Expressions.Expression.Lambda<Func<bool>>(propertyAccess).Compile();
|
||||
}
|
||||
|
||||
targetMethodInfo = newTargetType.GetMethod(this.methodName);
|
|
@ -8,36 +8,55 @@ using System.Windows;
|
|||
|
||||
namespace Stylet
|
||||
{
|
||||
public class EventCommand
|
||||
/// <summary>
|
||||
/// Created by ActionExtension, this can return a delegate suitable adding binding to an event, and can call a method on the View.ActionTarget
|
||||
/// </summary>
|
||||
public class EventAction
|
||||
{
|
||||
/// <summary>
|
||||
/// View whose View.ActionTarget we watch
|
||||
/// </summary>
|
||||
private FrameworkElement subject;
|
||||
|
||||
/// <summary>
|
||||
/// Property on the WPF element we're returning a delegate for
|
||||
/// </summary>
|
||||
private EventInfo targetProperty;
|
||||
|
||||
/// <summary>
|
||||
/// The MyMethod in {s:Action MyMethod}, this is what we call when the event's fired
|
||||
/// </summary>
|
||||
private string methodName;
|
||||
|
||||
public EventCommand(FrameworkElement subject, EventInfo targetProperty, string methodName)
|
||||
/// <summary>
|
||||
/// Create a new EventAction
|
||||
/// </summary>
|
||||
/// <param name="subject">View whose View.ActionTarget we watch</param>
|
||||
/// <param name="targetProperty">Property on the WPF element 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>
|
||||
public EventAction(FrameworkElement subject, EventInfo targetProperty, string methodName)
|
||||
{
|
||||
this.subject = subject;
|
||||
this.targetProperty = targetProperty;
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a delegate which can be added to the targetProperty
|
||||
/// </summary>
|
||||
public Delegate GetDelegate()
|
||||
{
|
||||
Delegate del = null;
|
||||
|
||||
var methodInfo = this.GetType().GetMethod("InvokeCommand", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
var parameterType = this.targetProperty.EventHandlerType;
|
||||
del = Delegate.CreateDelegate(parameterType, this, methodInfo);
|
||||
|
||||
return del;
|
||||
return Delegate.CreateDelegate(parameterType, this, methodInfo);
|
||||
}
|
||||
|
||||
private void InvokeCommand(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var target = View.GetActionTarget(this.subject);
|
||||
if (target == null)
|
||||
throw new Exception("Target not set");
|
||||
return;
|
||||
|
||||
var methodInfo = target.GetType().GetMethod(this.methodName);
|
||||
if (methodInfo == null)
|
Loading…
Reference in New Issue