简体   繁体   中英

MVVM Light - usage of RaiseCanExecuteChanged for RelayCommand

I'm using MVVM Pattern. Im my View, I have textboxes for Person details, which one of them is idBox. Also, the view consists of several buttons, which one of them is editModeBtn.

I want the editModeBtn to be enabled only when there is a valid int inside the idBox.

My Xaml (within view) for the editBtn looks like the following:

<Button x:Name="editModeBtn" Content="Edit" Command="{Binding ChangeToEditScreenCommand}"  CommandParameter="{Binding ElementName=idBox, Path=Text}"></Button>

In the corresponding viewModel, I have the following code:

private RelayCommand<string> _changeToEditScreenCommand;

    public RelayCommand<string> ChangeToEditScreenCommand
    {
        get
        {
            if (_changeToEditScreenCommand == null)
            {
                _changeToEditScreenCommand = new RelayCommand<string>((param) => ChangeToEditScreen(), (param) => CanEdit(param));
            }

            return _changeToEditScreenCommand;
        }
    }

Also, in the CanExecute method (CanEdit in my case), I want to check if the parameter (id) is set to a valid int and then return true. False, otherwise.

private bool CanEdit(string currentInsertedId)
    {
        int idValue;
        bool result = Int32.TryParse(currentInsertedId, out idValue);
        if (result)
        {
            if (idValue > 0) { return true; };
            return false;
        }
        return false;
    }

Basically, I want the canExecute method of the command to be invoked everytime something is written or removed from the idBox. Where should I put the RaiseCanExecuteChanged() of the command? If I haven't used MVVM, I could put it in the textBox textChanged event, but this is not the case here. Never used the RaiseCanExecuteChanged, so just want to ensure. Thanks!

Why are you going down the route of passing a CommandParameter ? Can't you just bind your TextBox.Text property to the VM with a UpdateSourceTrigger=PropertyChanged . This should get the bound property for Text in the VM get updated as soon as text in the TextBox changes, instead of the default which would be when the TextBox looses focus.

In your case this is the Behavior you seem to want. So with that all you need is a RelayCommand for your Command and not a RelayCommand<T> with a parameter.

So say simple xaml showing the above approach:

<TextBox Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}" />
<Button Command="{Binding ButtonCommand}"
        Content="My Button" />

and in the VM:

public string Title {
  get {
    return _title;
  }

  set {
    if (_title == value) {
      return;
    }

    _title = value;
    RaisePropertyChanged(() => Title);
  }
}

public RelayCommand ButtonCommand { get; private set; }

private bool CanEdit(string title) {
  int idValue;
  bool result = Int32.TryParse(title, out idValue);
  if (!result) {
    return false;
  }

  return idValue > 0;
}

ctor() {
  ButtonCommand = new RelayCommand(() => Debug.WriteLine("Called"), () => CanEdit(Title));
}

This by itself would achieve your query. However for your question abt usage of RaiseCanExecuteChanged() , In this example the property setter of Title is kind of similar to the textChanged event handler of the associated TextBox(I say this just cos that setter is now invoked everytime the text in the textbox changes)

So to absolutely guarantee your CanExecute() is invoked when the text changes, you can call ButtonCommand.RaiseCanExecuteChanged() from the Title property setter where you raise it's PropertyChanged event.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM