【问题标题】:WPF MVVM command canexecute enable/disable buttonWPF MVVM 命令可以执行启用/禁用按钮
【发布时间】:2015-08-04 10:51:31
【问题描述】:

我想在文本框属性文本不为空时启用 RibbonButton。当文本框属性文本为空时禁用 RibbonButton。我想在 ICommand 中使用 CanExecute 方法。我该怎么做?

查看:

 <Custom:RibbonButton
                        LargeImageSource="..\Shared\img\save_diskete.png"
                        Label="Save"
                        Command="{Binding ButtonCommand}">
                    </Custom:RibbonButton>

视图模型

class KomentarViewModel:BaseViewModel
    {
        #region Data
        private ICommand m_ButtonCommand;
        public ICommand ButtonCommand
        {
            get
            {
                return m_ButtonCommand;
            }
            set
            {
                m_ButtonCommand = value;
            }
        }
        private string textKomentar;
        public string TextKomentar
        {
            get
            {
                return this.textKomentar;
            }
            set
            {
                // Implement with property changed handling for INotifyPropertyChanged
                if (!string.Equals(this.textKomentar, value))
                {
                    textKomentar = value;
                    OnPropertyChanged("TextKomentar");
                }
            }
        }        
        private ObservableCollection<Komentar> allCommentsInc;
        public ObservableCollection<Komentar> AllCommentsInc
        {
            get
            {
                return allCommentsInc;
            }
            set
            {
                allCommentsInc = value;
                OnPropertyChanged("AllCommentsInc");
            }
        }

        public int idIncident { get; private set; }
        public Incident incident { get; private set; }
        #endregion

        #region Constructor
        public KomentarViewModel(int id)
        {
            CC_RK2Entities context = new CC_RK2Entities();
            this.idIncident = id;

            AllCommentsInc = new ObservableCollection<Komentar>(context.Komentar.Where(a => a.Incident_id == idIncident));
            incident = context.Incident.Where(a => a.id == idIncident).First();

            //ButtonCommand = new RelayCommand(new Action<object>(ShowMessage));
        }
        #endregion        

        #region Methods
        //ukaz napsany text
        public void ShowMessage(object obj)
        {
            //MessageBox.Show(obj.ToString());
            MessageBox.Show(this.TextKomentar);
        }
}

中继命令

namespace Admin.Shared.Commands
{
    class RelayCommand : ICommand
    {
        private Action<object> _action;

        public RelayCommand(Action<object> action)
        {
            _action = action;
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            return true;            
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
                _action(parameter);
        }

        #endregion
    }
}

【问题讨论】:

  • 我之前已经为文本框值启用了它,我实现的方法显示在下面

标签: c# .net wpf mvvm


【解决方案1】:

你需要像这样修改你的 RelayCommand 类

  class RelayCommand : ICommand
{
    private Action<object> _action;
    private Func<bool> _func;  

    public RelayCommand(Action<object> action,Func<bool> func)
    {
        _action = action;
        _func = func;
    }

    public void RaiseCanExecuteChanged()
    {
        if(CanExecuteChanged!=null)
            CanExecuteChanged(this,new EventArgs());
    }

    #region ICommand Members

    public bool CanExecute(object parameter)
    {
        if (_func != null)
           return _func();
        return true;
    }



    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _action(parameter);
    }

    #endregion
}

将 ButtonCommand 初始化为

ButtonCommand = new RelayCommand((s) => ShowMessage(s),()=>!string.IsNullOrEmpty(TextKomentar));

从 Text 属性的设置器中引发RaiseCanExcuteChanged

        public string TextKomentar
    {
        get
        {
            return this.textKomentar;
        }
        set
        {
            // Implement with property changed handling for INotifyPropertyChanged
            if (!string.Equals(this.textKomentar, value))
            {
                textKomentar = value;
                OnPropertyChanged("TextKomentar");
            }
            ButtonCommand.RaiseCanExecuteChanged();
        }
    }

【讨论】:

    【解决方案2】:

    为 canexecute 实现这个:

    public bool CanExecute(object parameter)
            {if(thistext available)
                return true; 
             else
                return false;  
            }
    

    因为,当 ICommandCanExecute 方法发生更改时,会引发 CanExecuteChanged。当某些可以更改canexecute 的命令时调用它。 并且可以执行更改应该改成这样:

    public event EventHandler CanExecuteChanged {
        add {
            CommandManager.RequerySuggested += value;
        }
        remove {
            CommandManager.RequerySuggested -= value;
        }
    }
    

    编辑

    在您的视图模型构造函数中:

    m_ButtonCommand= new RelayCommand(Submit, CanSubmit);
    
    now method for this submit:
     private bool CanSubmit(object obj)
            {
                if(thistext available)
                    return true; 
                 else
                    return false;  
    
            }
     public void Submit(object _)
      {//... code}
    
     public event EventHandler CanExecuteChanged {
            add {
                CommandManager.RequerySuggested += value;
            }
            remove {
                CommandManager.RequerySuggested -= value;
            }
        }
    

    这样做。

    【讨论】:

    • 但是,如何将 TextBox 的 text 属性传递给 CanExecute 方法?
    • np 如果对您有用,请将其标记为答案。
    【解决方案3】:

    简单来说,您需要以下内容:

    1. 让我们首先创建自己的delegate 命令:
    public class DelegateCommand : DelegateCommandBase
    {
        private Action _executeMethod;
        private Func<bool> _canExecute;
        
        public DelegateCommand(Action executeMethod)
            : this(executeMethod, () => true) {}
       
        public DelegateCommand(Action executeMethod, Func<bool> _canExecute): base()
        {
            if (executeMethod == null || _canExecute == null) {         
                  throw new ArgumentNullException(nameof(executeMethod),      
                                  Resources.DelegateCommandDelegatesCannotBeNull);
            }
    
            _executeMethod = executeMethod;
            _canExecute = _canExecute;
        }
    
        public void Execute() => _executeMethod();  
        public bool CanExecute() => _canExecute();
        
        protected override void Execute(object parameter) => Execute();
        protected override bool CanExecute(object parameter) => CanExecute();
    
        public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression)
        {
            ObservesPropertyInternal(propertyExpression);
            return this;
        }
        
        public DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
        {
            _canExecute = canExecuteExpression.Compile();
            ObservesPropertyInternal(canExecuteExpression);
            return this;
        }
    }
    

    这里,DelegateCommandBase 实际上来自 Prism.Commands 命名空间。

    如果您不使用 Prism 作为 WPF 的 MVVM 框架,您可以创建自己的 DelegateCommandBase 副本(寻找解决方案 here)。

    1. 在您的视图模型中,创建一个类型为 DelegateCommand 的成员并在构造函数中对其进行初始化:
    public class MyViewModel
    {
        private DelegateCommand _okCommand;
        public DelegateCommand OkCommand
        {
            get => _okCommand;
            set => SetProperty(ref _okCommand, value);
        }
            
        public MyViewModel() 
        {
            OkCommand = new PrismCommands.DelegateCommand(OkCommandHandler,
                                                          OkCanExecuteCommandHandler);
        }
        
        private void OkCommandHandler()
        {
            // ...
        } 
        
        // This is important part: need to return true/false based
        // on the need to enable or disable item
        private bool OkCanExecuteCommandHandler() =>
            return some_condition_to_enable_disable_item;   
    }
    

    注意:确保在每次发生可能影响some_condition_to_enable_disable_item 条件行为的更改时引发执行更改事件。

    例如,在Prism 的情况下,一旦发生与条件相关的更改(在我们的情况下为OkCommand.RaiseCanExecuteChanged();),您就可以调用RaiseCanExecuteChanged 方法。

    小提示:对于 Telerik WPF Controls,您需要调用 InvalidateCanExecute() 而不是 RaiseCanExecuteChanged()


    最后,我们的XAML 将如下所示:

    <Button x:Name="btnOk"
            Content="Ok"
            Command="{Binding OkCommand}"/>
    

    【讨论】:

      【解决方案4】:

      上次我使用来自Microsoft.Practices.Prism.dllMicrosoft.Practices.Prism.Commands 命名空间。 DelegateCommand 类有自己的 RaiseCanExecuteChanged() 方法。所以好处是您不必编写自己的ICommand 实现。

      XAML:

      <StackPanel>
          <CheckBox IsChecked="{Binding IsCanDoExportChecked}" />
          <Button Command="{Binding ExportCommand}" Content="Export" />
      </StackPanel>
      

      视图模型:

      public class ViewModel
      {
          public DelegateCommand ExportCommand { get; }
      
          public ViewModel()
          {
              ExportCommand = new DelegateCommand(Export, CanDoExptor);
          }
      
          private void Export()
          {
              //logic
          }
      
          private bool _isCanDoExportChecked;
      
          public bool IsCanDoExportChecked
          {
              get { return _isCanDoExportChecked; }
              set
              {
                  if (_isCanDoExportChecked == value) return;
      
                  _isCanDoExportChecked = value;
                  ExportCommand.RaiseCanExecuteChanged();
              }
          }
      
          private bool CanDoExptor()
          {
              return IsCanDoExportChecked;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-01-03
        • 2019-06-16
        • 1970-01-01
        • 1970-01-01
        • 2015-06-07
        • 2018-01-04
        • 2013-11-23
        • 2013-07-03
        • 1970-01-01
        相关资源
        最近更新 更多