我有一个Timer和三个按钮来控制它:Start,Stop和Pause.
每个按钮都绑定到一个RelayCommand.
我有一个类型的TimerState属性enum TimerState.(这对于设置各种GUI元素很有用.)
有没有办法以某种方式将RelayCommands的CanExecute功能绑定到TimerState属性?
目前,我有3个方法,如下所示:
private bool CanStartTimer()
{
return (TimerState == TimerState.Stopped || TimerState == TimerState.Paused);
}
在TimerState setter中,我调用
StartTimerCmd.RaiseCanExecuteChanged();
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法将RelayCommands的CanExecute状态绑定到TimerState之类的属性?
感谢您的任何见解.
我已经实现了一个类来处理命令,实际上它基于DelegateCommand,因为我正在使用PRISM但它可以很容易地被改为与RelayCommand或任何其他实现ICommand的类一起使用
它可能有错误,我还没有完全测试它,但它在我的场景中工作正常,这里是:
public class MyDelegateCommand<TViewModel> : DelegateCommand where TViewModel : INotifyPropertyChanged {
private List<string> _PropertiesToWatch;
public MyDelegateCommand(TViewModel viewModelInstance, Action executedMethod)
: base(executedMethod) {
}
public MyDelegateCommand(TViewModel viewModelInstance, Action executedMethod, Func<bool> canExecuteMethod)
: base(executedMethod, canExecuteMethod) {
}
/// <summary>
///
/// </summary>
/// <param name="viewModelInstance"></param>
/// <param name="executedMethod"></param>
/// <param name="selector"></param>
public MyDelegateCommand(TViewModel viewModelInstance, Action executedMethod, Func<bool> canExecuteMethod, Expression<Func<TViewModel, object>> propertiesToWatch)
: base(executedMethod, canExecuteMethod) {
_PropertiesToWatch = RegisterPropertiesWatcher(propertiesToWatch);
viewModelInstance.PropertyChanged += PropertyChangedHandler;
}
/// <summary>
/// handler that, everytime a monitored property changes, calls the RaiseCanExecuteChanged of the command
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e) {
if (_PropertiesToWatch.Contains(e.PropertyName)) {
this.OnCanExecuteChanged();
}
}
/// <summary>
/// giving an expression that identify a propriety or a list of properties, return the property names obtained from the expression
/// Examples on selector usage
/// proprietà singola:
/// entity => entity.PropertyName
/// proprietà multiple
/// entity => new { entity.PropertyName1, entity.PropertyName2 }
/// </summary>
/// <param name="selector"></param>
/// <returns></returns>
protected List<string> RegisterPropertiesWatcher(Expression<Func<TViewModel, object>> selector) {
List<string> properties = new List<string>();
System.Linq.Expressions.LambdaExpression lambda = (System.Linq.Expressions.LambdaExpression)selector;
if (lambda.Body is System.Linq.Expressions.MemberExpression) {
System.Linq.Expressions.MemberExpression memberExpression = (System.Linq.Expressions.MemberExpression)(lambda.Body);
properties.Add(memberExpression.Member.Name);
}
else if (lambda.Body is System.Linq.Expressions.UnaryExpression) {
System.Linq.Expressions.UnaryExpression unaryExpression = (System.Linq.Expressions.UnaryExpression)(lambda.Body);
properties.Add(((System.Linq.Expressions.MemberExpression)(unaryExpression.Operand)).Member.Name);
}
else if (lambda.Body.NodeType == ExpressionType.New) {
NewExpression newExp = (NewExpression)lambda.Body;
foreach (var argument in newExp.Arguments) {
if (argument is System.Linq.Expressions.MemberExpression) {
System.Linq.Expressions.MemberExpression mExp = (System.Linq.Expressions.MemberExpression)argument;
properties.Add(mExp.Member.Name);
}
else {
throw new SyntaxErrorException("Syntax Error, selector has to be an expression that returns a new object containing a list of properties, e.g.: s => new { s.Property1, s.Property2 }");
}
}
}
else {
throw new SyntaxErrorException("Syntax Error, selector has to be an expression that returns a new object containing a list of properties, e.g.: s => new { s.Property1, s.Property2 }");
}
return properties;
}
Run Code Online (Sandbox Code Playgroud)
}
请注意,我的解决方案意味着此命令必须与处理它的viewmodel连接,并且viewmodel必须实现INotifyPropertyChanged接口.
前两个构造函数在那里,所以命令向后兼容DelegateCommand但第三个是重要的,它接受一个linq表达式来指定要监视的属性
用法非常简单易懂,让我用方法在这里写,但当然你可以创建你的处理程序方法.假设你有一个名为MyViewModel的ViewModel,它有两个属性(PropertyX和PropertyY),它们引发了propertychanged事件,并且在其中某处你创建了一个SaveCommand实例,它看起来像这样:
this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
//execute
() => {
Console.Write("EXECUTED");
},
//can execute
() => {
Console.Write("Checking Validity");
return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
},
//properties to watch
(p) => new { p.PropertyX, p.PropertyY }
);
Run Code Online (Sandbox Code Playgroud)
也许我会在某处创建一篇关于此的文章,但我希望这个片段应该清楚
| 归档时间: |
|
| 查看次数: |
2828 次 |
| 最近记录: |