MVVM 将 RelayCommand CanExecute 绑定到属性?

2023-12-08

我有一个计时器和三个按钮来控制它:开始、停止和暂停。
每个按钮都绑定到一个 RelayCommand。
我有一个 TimerState 类型的属性enum TimerState。 (这对于设置各种 GUI 元素很有用。)
有没有办法以某种方式将 RelayCommands 的 CanExecute 功能绑定到 TimerState 属性?
目前,我有 3 种方法,如下所示:
private bool CanStartTimer() { return (TimerState == TimerState.Stopped || TimerState == TimerState.Paused); }
在 TimerState 设置器中,我调用

StartTimerCmd.RaiseCanExecuteChanged();  

是否有更好的方法将 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;
  }

}

请注意,我的解决方案意味着该命令必须与处理它的视图模型连接,并且视图模型必须实现 INotifyPropertyChanged 接口。

前两个构造函数在那里,因此该命令与 DelegateCommand 向后兼容,但第三个构造函数是重要的,它接受 linq 表达式来指定要监视的属性

用法非常简单且易于理解,让我在这里用方法来编写它,但当然您可以创建您的处理程序方法。假设您有一个名为 MyViewModel 的 ViewModel,它有两个引发 propertychanged 事件的属性(PropertyX 和 PropertyY),并且在其中的某个位置创建了 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 }
     );

也许我会在某个地方写一篇关于此的文章,但我希望这个片段应该很清楚

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MVVM 将 RelayCommand CanExecute 绑定到属性? 的相关文章

随机推荐

  • 使用 pywin32 Dispatch 在 Excel 中的命名工作表之后移动工作表

    我有大量文件 需要将其中的某个工作表复制到另一个工作簿 需要将它们放置在具有特定名称的工作表之后 同时保留要移动的工作表中的所有格式 我在另一个线程中看到 pywin32 将是可行的方法 但是我很难在指定的工作表 之后 复制此工作表 xl
  • 设计一个指令序列,以便在使用偏移量解码时执行其他操作

    这个问题是后续问题那个问题 要设置此问题的上下文 请考虑无空编程 这是一种将指令序列 shellcode 伪装成字符串的技术 在C编程语言中 字节0标志着字符串的结束 因此指令序列必须设计为不包含任何此类字节 否则它将被滥用的字符串操作函数
  • 文本框出现在单选按钮检查上

    我有以下 table td align center td table
  • pandas - groupby 和重新缩放值

    我想向此数据框添加一个重新缩放的列 I Value A 1 A 4 A 2 A 5 B 1 B 2 B 1 这样新列 我们称之为scale 遵循一个函数value每组的列I 该函数只是每个组范围的标准化 lambda x x min x m
  • 如何在单个 MSI 中部署多个项目?

    我的解决方案中有 3 个要部署的项目 是否有一种快速有效的方法可以使用 Visual Studio 的安装项目来使用一个 MSI 部署所有三个应用程序 并让用户在安装过程中决定要安装哪些应用程序 我有 3 个单独应用程序的设置项目 我还有一
  • Google 表格中的一项功能可处理多个工作表

    在 Google Sheets 中我必须重复一个函数 因为getSheetByName 不接受一系列工作表 它只接受一张工作表 有没有一种方法可以让一个函数循环指定的工作表 不是所有工作表 i e 表 1 表 2 等 function re
  • 蓝牙SPP接收到的一些包帧会丢失还是?

    我使用android示例代码进行修改 只想收到包裹 但是 我的代码只在这里修改 private final Handler mHandler new Handler Override public void handleMessage Me
  • 在 grails 的 jasper 报告中以 pdf 格式显示新安装的字体

    我正在使用 iReport 4 5 0 和 grails 2 1 1 我想对 pdf 格式的报告中的某些文本使用 Canterbury 字体 因此我使用 iReport 设计器将该字体分配给我想要的文本 我还进入 iReport 设计器的工
  • 熟悉 MVC - 如何使用会话逻辑、附加类和后台逻辑

    在编写 PHP 代码时 我决定放弃意大利面条式代码并尝试实现 MVC 为了实现MVC框架 我发泄本文文章给了我一个良好的开端 我成功地创建了我的网站并开发了前端 现在 我正在尝试使用会话和其他会员区功能来实现后端 我的大脑充满了新信息 我的
  • 查找两个字符串数组之间的非公共元素

    有一个问题是如何找到两个字符串数组之间的非公共元素 例如 String a a b c d String b b c O p should be a d 我已经尝试过以下方法 但请告知是否有其他有效的方法来实现相同的目标 String a
  • TLabel 和 TGroupbox 标题在调整大小时闪烁

    所以 我有一个应用程序加载不同的插件并创建一个 每个 TPageControl 上都有一个新选项卡 每个 DLL 都有一个与其关联的 TForm 创建表单时将其父级 hWnd 作为新的 TTabSheet 由于就 VCL 而言 TTabSh
  • WebResource.axd 不适用于 Internet Explorer 11

    我们正在针对新的 Windows 8 1 IE 11 浏览器 classic 和 Metro 测试我们的网站 有一个Javascript文件嵌入WebResource axd The WebResource可以在 Firefox Googl
  • 将 H2 数据传输到 PostgreSQL

    我正在从 H2 数据库过渡到 PostgreSQL 据我发现 在 H2 上执行 SCRIPT TO 命令时创建的 SQL 转储包含几个不适当的结构 Unicode 数据用函数 STRINGDECODE unicode data 包装 二进制
  • 将OutputStream发送到浏览器并让浏览器保存它[重复]

    这个问题在这里已经有答案了 我想从 Rich Faces 数据表导出数据 我已经从数据表中的数据创建了outputStream 现在想将这个OutputStream发送到浏览器并让它保存 我怎样才能做到这一点 FileOutputStrea
  • 无法在无 cookie Web 应用程序上创建 asp.net 会话

    我有一个无cookie的基于asp net 4 5的网络应用程序
  • HTML5 localStorage 不适用于 Android WebView

    我正在使用 Buzztouch 为客户端制作移动应用程序 因此 html 页面不在应用程序内 它们是通过 JSON 从服务器加载的 客户希望应用程序上有一个屏幕 用户可以在其中将详细信息输入时间表并将其存储在手机上 我尝试使用 localS
  • 如何计算Android应用程序中两点之间的距离

    在我的应用程序中 我试图计算一个人从一个地方到另一个地方的旅行距离 为此 我使用半正矢公式 R earth s radius mean radius 6 371km lat lat2 lat1 long long2 long1 a sin
  • 为什么线程不停止?

    我的服务生成一个新线程 并根据通常推荐java中断 的方法 当我停止服务时 我会在 onDestroy 中停止线程 服务停止 到达中断代码 然而 很快线程就会从 Runnable 的开头重新启动 public class DoScan ex
  • 使用欧氏距离在 numpy 数组列表中查找 numpy 数组的最近邻居

    我有一个 n 维向量 我想使用欧几里得距离在 n 维向量列表中找到它的 k 个最近邻 我编写了以下代码 k 10 它可以工作 但运行速度太慢 我想知道是否有更优化的解决方案 def nearest neighbors value array
  • MVVM 将 RelayCommand CanExecute 绑定到属性?

    我有一个计时器和三个按钮来控制它 开始 停止和暂停 每个按钮都绑定到一个 RelayCommand 我有一个 TimerState 类型的属性enum TimerState 这对于设置各种 GUI 元素很有用 有没有办法以某种方式将 Rel