Change the activated property of a WPF control (button) according to the contents of the text box

advertisements

Im looking for a solution in WPF to change the IsEnabled property of a button based on the content of a textbox. The TextBox holds a numeric value. If the value is greater than a certain value the IsEnabled property of the button should be set to true, as long as it is below this value the property should be false. I have been looking around but couldn't find a proper solution. What i found here on CodeProject is almost what im looking for. But the problem is that this approach just checks if any content is in the textbox. But i need to check/compare the numeric content.

I would prefer to find a way to do it in XAML. Alternatively i could implement it also in my ViewModel. But i dont have an idea how to do it! I was thinking about to notify the button via my INotifyChanged event from the property that is shown in the textbox. But i couldnt find out how.

Followed some code. But, sorry, there is nothing beside the textbox and the button since i couldnt find a way to solve that.

<TextBox Name ="tbCounter" Text ="{Binding CalcViewModel.Counter, Mode=OneWay}" Background="LightGray" BorderBrush="Black" BorderThickness="1"
              Height="25" Width="50"
              commonWPF:CTextBoxMaskBehavior.Mask="Integer"
              commonWPF:CTextBoxMaskBehavior.MinimumValue="0"
              commonWPF:CTextBoxMaskBehavior.MaximumValue="1000"
              IsReadOnly="True"/>
<Button Name="btnResetCount" Focusable="True" Content="Reset" Command="{Binding Path=CalcViewModel.ResetCounter}" Style="{StaticResource myBtnStyle}"
              Width="100" Height="25">

Is there a common way to set the IsEnabled property of a control based on a property/value in the XAML or in the ViewModel?

EDIT This is my ViewModel, i extracted the related members and properties only otherwise the post would be too long:

class CalcViewModel:INotifyPropertyChanged
{
    private CCalc _calc;

    public int Counter
    {
        get
        { return _calc.Counter; }
        set{ _calc.Counter = value;}
    }

    public event PropertyChangedEventHandler PropertyChanged;

    void ResetCounterExecute()
    { _calc.Counter = 0; }

    bool CanResetCounterExecute()
    {
        if (_calc.Counter > 0)
        { return true; }
        else
        { return false; }
    }

    public ICommand ResetCounter
    { get { return new RelayCommand(ResetCounterExecute, CanResetCounterExecute); } }

    public CCalcViewModel()
    {
        this._calc = new CCalcViewModel();
        this._calc.PropertyChanged += new PropertyChangedEventHandler(OnCalcPropertyChanged);
    }
    private void OnCalcPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.RaisePropertyChanged(e.PropertyName);
    }

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }


You want to combine an element property binding:

IsEnabled={Binding ElementName=Textbox, Path=Text}

With a valueconverter

IsEnabled={Binding ElementName=Textbox, Path=Text, Converter={StaticResource IsAtLeastValueConverter}}

IsAtLeastValueConverter.cs

namespace WpfPlayground
{
    public class IsAtLeastValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (System.Convert.ToInt32(value) > 5)
            {
                return true;
            }
            return false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }
}

Oh I forgot you'll need to add this to your control:

<Window.Resources>
    <wpfPlayground:IsAtLeastValueConverter x:Key="IsAtLeastValueConverter" />
</Window.Resources>


Edit: VM Version

I've put in elipsis (...) where I didn't make changes to your code.

<Button ... IsEnabled={Binding Path=ButtonIsEnabled} ...>

class CalcViewModel:INotifyPropertyChanged
{
    private CCalc _calc;
    private bool _buttonIsEnabled;
    public ButtonIsEnabled {
        get { return _buttonIsEnabled; }
        set {
            _buttonIsEnabled = value;
            RaisePropertyChanged("ButtonIsEnabled");
        }
    }

    public int Counter
    {
        get
        { return _calc.Counter; }
        set{
            _calc.Counter = value;
            _buttonIsEnabled = _calc.Counter > 5;
        }
    }
    ...
}

So what happens here is when you change the counter value, you set the ButtonIsEnabled property which raises the property changed event and updates the button on the form with whatever logic you're using to determine if the button should be enabled.

Edit: You might need to remove that Binding=OneWay from the textbox, I'm not sure if it will initiate the set property if you're using that setting.