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"
|
xmlns:s="http://github.com/canton7/Stylet"
|
||||||
Height="300" Width="300">
|
Height="300" Width="300">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBox Text="{Binding Name}"/>
|
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
|
||||||
<Button Command="{s:Action SayHello}">Say Hello</Button>
|
<Button Command="{s:Action SayHello}">Say Hello</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
@ -9,13 +9,22 @@ namespace Stylet.Samples.Hello
|
||||||
{
|
{
|
||||||
class ShellViewModel : Screen
|
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()
|
public ShellViewModel()
|
||||||
{
|
{
|
||||||
this.DisplayName = "Hello, Stylet";
|
this.DisplayName = "Hello, Stylet";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanSayHello
|
||||||
|
{
|
||||||
|
get { return !String.IsNullOrEmpty(this.Name); }
|
||||||
|
}
|
||||||
public void SayHello()
|
public void SayHello()
|
||||||
{
|
{
|
||||||
MessageBox.Show(String.Format("Hello, {0}", this.Name)); // Don't do this
|
MessageBox.Show(String.Format("Hello, {0}", this.Name)); // Don't do this
|
||||||
|
|
|
@ -30,13 +30,13 @@ namespace Stylet
|
||||||
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
|
var propertyAsDependencyProperty = valueService.TargetProperty as DependencyProperty;
|
||||||
if (propertyAsDependencyProperty != null && propertyAsDependencyProperty.PropertyType == typeof(ICommand))
|
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;
|
var propertyAsEventInfo = valueService.TargetProperty as EventInfo;
|
||||||
if (propertyAsEventInfo != null)
|
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();
|
return ec.GetDelegate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,23 +13,52 @@ using Expressions = System.Linq.Expressions;
|
||||||
|
|
||||||
namespace Stylet
|
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;
|
private FrameworkElement subject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method name. E.g. if someone's gone Buttom Command="{s:Action MyMethod}", this is MyMethod.
|
||||||
|
/// </summary>
|
||||||
private string methodName;
|
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;
|
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 MethodInfo targetMethodInfo;
|
||||||
|
|
||||||
private object target;
|
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.subject = subject;
|
||||||
this.methodName = methodName;
|
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
|
private string GuardName
|
||||||
|
@ -37,7 +66,7 @@ namespace Stylet
|
||||||
get { return "Can" + this.methodName; }
|
get { return "Can" + this.methodName; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateGuardHandler()
|
private void UpdateGuardAndMethod()
|
||||||
{
|
{
|
||||||
var newTarget = View.GetActionTarget(this.subject);
|
var newTarget = View.GetActionTarget(this.subject);
|
||||||
MethodInfo targetMethodInfo = null;
|
MethodInfo targetMethodInfo = null;
|
||||||
|
@ -50,9 +79,9 @@ namespace Stylet
|
||||||
var guardPropertyInfo = newTargetType.GetProperty(this.GuardName);
|
var guardPropertyInfo = newTargetType.GetProperty(this.GuardName);
|
||||||
if (guardPropertyInfo != null && guardPropertyInfo.PropertyType == typeof(bool))
|
if (guardPropertyInfo != null && guardPropertyInfo.PropertyType == typeof(bool))
|
||||||
{
|
{
|
||||||
var param = Expressions.Expression.Parameter(typeof(bool), "returnValue");
|
var targetExpression = Expressions.Expression.Constant(newTarget);
|
||||||
var propertyAccess = Expressions.Expression.Property(param, guardPropertyInfo);
|
var propertyAccess = Expressions.Expression.Property(targetExpression, guardPropertyInfo);
|
||||||
this.guardPropertyGetter = Expressions.Expression.Lambda<Func<bool>>(propertyAccess, param).Compile();
|
this.guardPropertyGetter = Expressions.Expression.Lambda<Func<bool>>(propertyAccess).Compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
targetMethodInfo = newTargetType.GetMethod(this.methodName);
|
targetMethodInfo = newTargetType.GetMethod(this.methodName);
|
|
@ -8,36 +8,55 @@ using System.Windows;
|
||||||
|
|
||||||
namespace Stylet
|
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;
|
private FrameworkElement subject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Property on the WPF element we're returning a delegate for
|
||||||
|
/// </summary>
|
||||||
private EventInfo targetProperty;
|
private EventInfo targetProperty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MyMethod in {s:Action MyMethod}, this is what we call when the event's fired
|
||||||
|
/// </summary>
|
||||||
private string methodName;
|
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.subject = subject;
|
||||||
this.targetProperty = targetProperty;
|
this.targetProperty = targetProperty;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return a delegate which can be added to the targetProperty
|
||||||
|
/// </summary>
|
||||||
public Delegate GetDelegate()
|
public Delegate GetDelegate()
|
||||||
{
|
{
|
||||||
Delegate del = null;
|
|
||||||
|
|
||||||
var methodInfo = this.GetType().GetMethod("InvokeCommand", BindingFlags.NonPublic | BindingFlags.Instance);
|
var methodInfo = this.GetType().GetMethod("InvokeCommand", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
var parameterType = this.targetProperty.EventHandlerType;
|
var parameterType = this.targetProperty.EventHandlerType;
|
||||||
del = Delegate.CreateDelegate(parameterType, this, methodInfo);
|
return Delegate.CreateDelegate(parameterType, this, methodInfo);
|
||||||
|
|
||||||
return del;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InvokeCommand(object sender, RoutedEventArgs e)
|
private void InvokeCommand(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var target = View.GetActionTarget(this.subject);
|
var target = View.GetActionTarget(this.subject);
|
||||||
if (target == null)
|
if (target == null)
|
||||||
throw new Exception("Target not set");
|
return;
|
||||||
|
|
||||||
var methodInfo = target.GetType().GetMethod(this.methodName);
|
var methodInfo = target.GetType().GetMethod(this.methodName);
|
||||||
if (methodInfo == null)
|
if (methodInfo == null)
|
Loading…
Reference in New Issue