WIP towards ActionCommand using expression trees. Needs a bit more work to finish it off...

This commit is contained in:
Antony Male 2014-02-25 13:37:16 +00:00
parent 6ee8927137
commit 24c32e5290
1 changed files with 48 additions and 7 deletions

View File

@ -9,13 +9,16 @@ using System.Windows;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using Expressions = System.Linq.Expressions;
namespace Stylet namespace Stylet
{ {
public class ActionCommand : ICommand public class ActionCommand : ICommand
{ {
private FrameworkElement subject; private FrameworkElement subject;
private string methodName; private string methodName;
private PropertyInfo guardPropertyInfo; private Func<bool> guardPropertyGetter;
private Func<object> methodInvoker;
private object target; private object target;
@ -26,6 +29,7 @@ namespace Stylet
this.UpdateGuardHandler(); this.UpdateGuardHandler();
DependencyPropertyDescriptor.FromProperty(View.TargetProperty, typeof(View)).AddValueChanged(this.subject, (o, e) => this.UpdateGuardHandler()); DependencyPropertyDescriptor.FromProperty(View.TargetProperty, typeof(View)).AddValueChanged(this.subject, (o, e) => this.UpdateGuardHandler());
} }
@ -37,12 +41,18 @@ namespace Stylet
private void UpdateGuardHandler() private void UpdateGuardHandler()
{ {
var newTarget = View.GetTarget(this.subject); var newTarget = View.GetTarget(this.subject);
this.guardPropertyInfo = null;
this.guardPropertyGetter = null;
if (newTarget != null) if (newTarget != null)
{ {
var guardPropertyInfo = newTarget.GetType().GetProperty(this.GuardName); var guardPropertyInfo = newTarget.GetType().GetProperty(this.GuardName);
if (guardPropertyInfo != null && guardPropertyInfo.PropertyType == typeof(bool)) if (guardPropertyInfo != null && guardPropertyInfo.PropertyType == typeof(bool))
this.guardPropertyInfo = guardPropertyInfo; {
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 oldTarget = this.target as INotifyPropertyChanged; var oldTarget = this.target as INotifyPropertyChanged;
@ -52,12 +62,43 @@ namespace Stylet
this.target = newTarget; this.target = newTarget;
var inpc = newTarget as INotifyPropertyChanged; var inpc = newTarget as INotifyPropertyChanged;
if (this.guardPropertyInfo != null && inpc != null) if (this.guardPropertyGetter != null && inpc != null)
inpc.PropertyChanged += this.PropertyChangedHandler; inpc.PropertyChanged += this.PropertyChangedHandler;
this.UpdateCanExecute(); this.UpdateCanExecute();
} }
private void UpdateMethodInvoker()
{
if (this.target == null)
throw new ArgumentException("Target not set");
var methodInfo = this.target.GetType().GetMethod(this.methodName);
if (methodInfo == null)
throw new Exception(String.Format("Unable to find method {0} on {1}", this.methodName, this.target.GetType().Name));
var target = Expressions.Expression.Constant(this.target);
var param = Expressions.Expression.Parameter(typeof(object), "parameter");
Expressions.Expression call;
var methodParameters = methodInfo.GetParameters();
if (methodParameters.Length == 0)
{
call = Expressions.Expression.Call(target, methodInfo);
}
else if (methodParameters.Length == 1)
{
var convertedParam = Expressions.Expression.Convert(param, methodParameters[0].ParameterType);
call = Expressions.Expression.Call(target, methodInfo, convertedParam);
}
else
{
throw new Exception(String.Format("Method {0} must accept either 0 or 1 arguments", this.methodName));
}
this.methodInvoker = Expressions.Expression.Lambda<Func<object>>(call, param).Compile();
}
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{ {
if (String.IsNullOrEmpty(e.PropertyName) || e.PropertyName == this.GuardName) if (String.IsNullOrEmpty(e.PropertyName) || e.PropertyName == this.GuardName)
@ -75,10 +116,10 @@ namespace Stylet
public bool CanExecute(object parameter) public bool CanExecute(object parameter)
{ {
if (this.guardPropertyInfo == null) if (this.guardPropertyGetter == null)
return true; return true;
return (bool)this.guardPropertyInfo.GetValue(this.target); return this.guardPropertyGetter();
} }
public event EventHandler CanExecuteChanged; public event EventHandler CanExecuteChanged;
@ -86,7 +127,7 @@ namespace Stylet
public void Execute(object parameter) public void Execute(object parameter)
{ {
if (this.target == null) if (this.target == null)
throw new Exception("Target not set"); throw new ArgumentException("Target not set");
var methodInfo = this.target.GetType().GetMethod(this.methodName); var methodInfo = this.target.GetType().GetMethod(this.methodName);
if (methodInfo == null) if (methodInfo == null)