如何在 WPF 中使用 ICommand 中的 CanExecute 方法

Posted

技术标签:

【中文标题】如何在 WPF 中使用 ICommand 中的 CanExecute 方法【英文标题】:How to use the CanExecute Method from ICommand on WPF 【发布时间】:2015-07-12 04:42:18 【问题描述】:

如何使用ICommand接口中的CanExecute方法?


在我的示例中,我有一个 SaveCommand,仅当对象可保存时才启用它。我的 Savebutton 的 XAML 代码如下所示:

<Button Content="Save" Command="Binding SaveCommand, Mode=TwoWay" />

这是我的存档类的代码:

class Save : ICommand

    public MainWindowViewModel viewModel  get; set; 

    public Save(MainWindowViewModel viewModel)
    
        this.viewModel = viewModel;
    

    public bool CanExecute(object parameter)
    

        if (viewModel.IsSaveable == false)
            return false;
        return true;
    

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    
        viewModel.Save();
    

ViewModel 中的保存属性如下所示:

    public ICommand SaveCommand
    
        get
        
            saveCommand = new Save(this);
            return saveCommand;
        
        set
        
            saveCommand = value;
        
    

这个构造不起作用。当 isSaveable 为 true 时,按钮不会启用自身。

【问题讨论】:

绑定到命令时是否需要双向绑定? 没想到我会把整个视图模型传递给命令(现在我不知道是什么给了我这个想法!)。即使与我的问题无关,这里看到的示例代码也从废品堆中保存了我的 UI 设计的一个关键部分。 【参考方案1】:

不要定义您自己的ICommand 实现,而是使用RelayCommand

在下面的示例代码中,当用户在TextBox 中输入内容时,保存Button 被启用。

XAML:

<Window x:Class="RelayCommandDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel HorizontalAlignment="Center">
        <TextBox Text="Binding Name, UpdateSourceTrigger=PropertyChanged" Margin="5" Width="120"/>
        <Button Content="Save" Command="Binding SaveCommand" Margin="3"/>
    </StackPanel>
</Window>

后面的代码:

using System;
using System.Windows;
using System.Windows.Input;

namespace RelayCommandDemo

    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();

            DataContext = new VM();
        
    
    public class VM
    
        public String Name  get; set; 

        private ICommand _SaveCommand;

        public ICommand SaveCommand
        
            get  return _SaveCommand; 
        

        public VM()
        
            _SaveCommand = new RelayCommand(SaveCommand_Execute, SaveCommand_CanExecute);
        

        public void SaveCommand_Execute()
        
            MessageBox.Show("Save Called");
        

        public bool SaveCommand_CanExecute()
        
            if (string.IsNullOrEmpty(Name))
                return false;
            else
                return true;
        
    

    public class RelayCommand : ICommand
    
        public event EventHandler CanExecuteChanged
        
            add  CommandManager.RequerySuggested += value; 
            remove  CommandManager.RequerySuggested -= value; 
        
        private Action methodToExecute;
        private Func<bool> canExecuteEvaluator;
        public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
        
            this.methodToExecute = methodToExecute;
            this.canExecuteEvaluator = canExecuteEvaluator;
        
        public RelayCommand(Action methodToExecute)
            : this(methodToExecute, null)
        
        
        public bool CanExecute(object parameter)
        
            if (this.canExecuteEvaluator == null)
            
                return true;
            
            else
            
                bool result = this.canExecuteEvaluator.Invoke();
                return result;
            
        
        public void Execute(object parameter)
        
            this.methodToExecute.Invoke();
        
    

【讨论】:

您可能想解释一下为什么您建议使用RelayCommand

以上是关于如何在 WPF 中使用 ICommand 中的 CanExecute 方法的主要内容,如果未能解决你的问题,请参考以下文章

2022-03-23 WPF面试题 WPF中的命令设计模式和ICommand是什么?

2022-03-23 WPF面试题 WPF中的命令设计模式和ICommand是什么?

WPF中的Command命令详解

为什么必须公开ICommand对象才能在WPF中正常工作?

在 WPF UserControl 中附加 ICommand

WPF ICommand CanExecute(): RaiseCanExecuteChanged() 还是通过 DispatchTimer 自动处理?