WPF MVVM command canexecute enable/disable button

后端 未结 4 805
悲哀的现实
悲哀的现实 2020-12-03 14:51

I want to enable RibbonButton when textbox property text isn\'t null. Disable RibbonButton when textbox property text is null. I want to use CanExecute method in ICommand fo

相关标签:
4条回答
  • 2020-12-03 15:30

    You need to modify your RelayCommand class like this

      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
    }
    

    Initialize ButtonCommand as

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

    RaiseCanExcuteChanged from the setter of Text property

            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();
            }
        }
    
    0 讨论(0)
  • implement this for canexecute:

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

    Since, CanExecuteChanged is raised when the CanExecute method of an ICommand gets changed. it gets invoked when some command that could change canexecute. and can execute changed should be changed to this:

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

    EDIT

    in your view model constructor:

    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;
            }
        }
    

    do it like this.

    0 讨论(0)
  • 2020-12-03 15:33

    Last time I used Microsoft.Practices.Prism.Commands namesapce from Microsoft.Practices.Prism.dll. Class DelegateCommand has own RaiseCanExecuteChanged() method. So the benifit is you don't have to write yout own implementation of ICommand.

    XAML:

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

    ViewModel:

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-03 15:47

    In straightforward words, you need the following:

    1. Let's first create our own delegate command:
    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;
        }
    }
    

    Here, DelegateCommandBase is actually from Prism.Commands namespace.

    If you don't use Prism as an MVVM framework for WPF, you can create your own copy of DelegateCommandBase (look for the solution here).

    1. In your View Model, create a member with type DelegateCommand and initialize it in the constructor:
    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;   
    }
    

    Note: make sure to raise execution changed event, every time something changes that can affect some_condition_to_enable_disable_item condition behavior.

    For example, in the case of Prism, you can call RaiseCanExecuteChanged method once a change happens related to the condition (in our case OkCommand.RaiseCanExecuteChanged();).

    Small hint: for Telerik WPF Controls, you need to call InvalidateCanExecute() instead of RaiseCanExecuteChanged().


    Finally, our XAML will look like this:

    <Button x:Name="btnOk"
            Content="Ok"
            Command="{Binding OkCommand}"/>
    
    0 讨论(0)
提交回复
热议问题