Reputation: 215
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 for it. How can I do it?
View:
<Custom:RibbonButton
LargeImageSource="..\Shared\img\save_diskete.png"
Label="Save"
Command="{Binding ButtonCommand}">
</Custom:RibbonButton>
ViewModel
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);
}
}
RelayCommand
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
}
}
Upvotes: 18
Views: 55265
Reputation: 8350
In straightforward words, you need the following:
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).
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}"/>
Upvotes: 1
Reputation: 12315
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();
}
}
Upvotes: 22
Reputation: 9506
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;
}
}
Upvotes: 0
Reputation: 1863
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.
Upvotes: 3