4

I have a very simple application with a TextBox and a Button. When the text entered into the TextBox exceeds 5 characters in length, the button will be enabled. Here is the code for my ViewModel:

private string _text { get; set; }
public string Text
{
    get { return _text; }
    set
    {
        _text = value;
        OnPropertyChanged("Text");
    }
}

private ICommand _buttonCommand;
public ICommand ButtonCommand
{
    get
    {
        if (_buttonCommand == null)
        {
            _buttonCommand = new RelayCommand(
                param => this.ButtonCommandExecute(), 
                param => this.ButtonCommandCanExecute()
            );
        }
        return _buttonCommand;
    }
}

private bool ButtonCommandCanExecute()
{
    if (this.Text.Length < 5)
    {
        return false;
    }
    else
    {
        return true;
    }
}

private void ButtonCommandExecute()
{
    this.Text = "Text changed";
}

public MainWindowViewModel()
{
    //
}

The TextBox and Button are bound using this XAML:

<Button Content="Button" HorizontalAlignment="Left" 
                Margin="185,132,0,0" VerticalAlignment="Top" Width="120"
                Command="{Binding Path=ButtonCommand}" />

<TextBox HorizontalAlignment="Left" Height="23" 
         Margin="185,109,0,0" TextWrapping="Wrap" 
         Text="{Binding Path=Text, Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>

The DataContext appears to be set correctly, but here it is just because I am a WPF beginner:

private MainWindowViewModel view_model;

public MainWindow()
{
    InitializeComponent();

    view_model = new MainWindowViewModel();

    this.DataContext = view_model;
}

When I type into the TextBox, the Button never enables.

user3761858
  • 231
  • 2
  • 6
  • 13
  • 4
    Does it enable/disable correctly if you tab out of the TextBox? The default binding mode for `TextBox.Text` is `OnLostFocus`, so the data wouldn't persist back to your VM until the `TextBox` loses focus. To change that, you can set the binding `Mode` property to `PropertyChanged`. Also, what type of RelayCommand are you using? If it's the MVVM light relay command, then it should automatically raise the `CanExecuteChanged` and requery `CanExecute` whenever a property changes, however not all relay commands are like that. – Rachel Sep 13 '14 at 23:23
  • That was also an issue, thanks very much Rachel. – user3761858 Sep 13 '14 at 23:28

3 Answers3

14

Some implementations of ICommand interface have special method to notify whether "CanExecute" has changed. RelayCommand class (MVVM Light) has such method.

private string _text;
public string Text
{
    get { return _text; }
    set
    {
        _text = value;
        OnPropertyChanged("Text");

        // There is a special RelayCommand method to notify "CanExecute" changed.
        // After this call, the "CanExecute" state is "re-evaluated" automatically by binding using CanExecute Func passed into RelayCommand constructor.
        _buttonCommand.RaiseCanExecuteChanged();
    }
}

private RelayCommand _buttonCommand;
public ICommand ButtonCommand
{
    get
    {
        if (_buttonCommand == null)
        {
            _buttonCommand = new RelayCommand(
                param => this.ButtonCommandExecute(), 
                param => this.ButtonCommandCanExecute()
            );
        }
        return _buttonCommand;
    }
}

This question can be useful: What is CanExecuteChanged for?

Community
  • 1
  • 1
  • 5
    This is the correct answer as it allows the ICommand to work as designed and doesn't require extra properties or binding. – TyCobb Sep 14 '14 at 01:34
2

Actually you have to make Bool Property to bind to the IsEnabled property of the Button Control. And set this property to true when your text in Textbox is more than five character - you have to do this in Setter of Text property Because this is what being called when you type in your TextBox.

Basic About Commands :- These are basically to Report the e.g Clicks events to the C# code say your Viewmodel/Page.cs . So that you can perform some Tasks. It is not related to anything about Enabling and disabling of button.

Follow the Code :-

private string _text { get; set; }
public string Text
{
    get { return _text; }
    set
    {
        _text = value;

        if(_text.Length  > 5)
        // Enable button here
        // and command does not enable Buttons they are basically report the clicks events.
        IsButtonEnabled = true;

        OnPropertyChanged("Text");
    }
}

For Enabling Button Create Bool type property Called IsButtonEnabled and bind this property to your Button in Xaml.

private bool _IsButtonEnabled { get; set; }
public bool IsButtonEnabled
{
    get { return _IsButtonEnabled ; }
    set
    {
        _IsButtonEnabled = value;
        OnPropertyChanged("IsButtonEnabled");
    }
}

In Xaml :-

<Button Content="Button" HorizontalAlignment="Left" 

             IsEnabled="{Binding IsButtonEnabled}"

            Margin="185,132,0,0" VerticalAlignment="Top" Width="120"
            Command="{Binding Path=ButtonCommand}" />
loop
  • 9,002
  • 10
  • 40
  • 76
  • My man, thanks a bunch! I did what you stated as it makes sense, but could you elaborate on the binding of IsButtonEnabled? Do I bind this to the IsEnabled property of my Button? – user3761858 Sep 13 '14 at 23:23
  • @user3761858 yes bro. I have added a code for it in bottom of the ans. :) – loop Sep 13 '14 at 23:25
  • 3
    Note: no additional property is needed. Store the command (field) as `RelayCommand` and just call `RelayCommand.RaiseCanExecuteChanged();` after `OnPropertyChanged("Text")`. – Sergey Vyacheslavovich Brunov Sep 14 '14 at 00:03
  • @SergeyBrunov You mean to say It will enable the button if it is disabbled before ? – loop Sep 14 '14 at 00:10
  • @loop, yes, because `Button` listens to the [ICommand.CanExecuteChanged Event](http://msdn.microsoft.com/en-us/library/system.windows.input.icommand.canexecutechanged%28v=vs.100%29.aspx). Please see my answer. – Sergey Vyacheslavovich Brunov Sep 14 '14 at 00:18
  • 1
    @SergeyBrunov Thanks I did not know that :) I try it. just going to sleep. using my tab right now. – loop Sep 14 '14 at 00:36
-2

Try this Little modification of your code and tell me if it Works:

private string _text { get; set; }
public string Text
{
    get { return _text; }
    set
    {
        _text = value;
        OnPropertyChanged("Text");
        ButtonCommandCanExecute();
    }
}

private ICommand _buttonCommand;
public ICommand ButtonCommand
{
    get
    {
        if (_buttonCommand == null)
        {
            _buttonCommand = new RelayCommand(
                param => this.ButtonCommandExecute(), 
                param => this.ButtonCommandCanExecute()
            );
        }
        return _buttonCommand;
    }
}

private bool ButtonCommandCanExecute()
{
    if (this.Text.Length < 5)
    {
        return false;
    }
    else
    {
        return true;
    }
}

private void ButtonCommandExecute()
{
    this.Text = "Text changed";
}

public MainWindowViewModel()
{
    //
}
ericpap
  • 2,917
  • 5
  • 33
  • 52
  • 1
    this will not going to be work:- where is the code for enabling/disabling of button ? – loop Sep 13 '14 at 23:27