Изменить включенное свойство элемента управления (кнопки) WPF на основе содержимого текстового поля

Я ищу решение в WPF для изменения свойства IsEnabled кнопки на основе содержимого текстового поля. TextBox содержит числовое значение. Если значение больше определенного значения, свойство IsEnabled кнопки должно быть установлено в true, если оно ниже этого значения, свойство должно иметь значение false. Я искал вокруг, но не мог найти правильное решение. То, что я нашел здесь на CodeProject, - почти то, что я ищу. Но проблема в том, что этот подход просто проверяет, есть ли какой-либо контент в текстовом поле. Но мне нужно проверить / сравнить числовой контент.

Я бы предпочел найти способ сделать это в XAML. В качестве альтернативы я мог бы реализовать это также в моей ViewModel. Но у меня нет идеи, как это сделать! Я думал о том, чтобы уведомить кнопку через событие INotifyChanged из свойства, которое отображается в текстовом поле. Но я не мог узнать как.

Последовал какой-то код. Но, извините, нет ничего кроме текстового поля и кнопки, так как я не мог найти способ решить это.

<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">

Есть ли общий способ установить свойство IsEnabled элемента управления на основе свойства / значения в XAML или ViewModel?

РЕДАКТИРОВАТЬ Это моя ViewModel, я извлек связанные элементы и свойства только в противном случае сообщение будет слишком длинным:

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

3 ответа

Решение

Вы хотите объединить привязку свойства элемента:

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

С преобразователем стоимости

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

О, я забыл, что вам нужно добавить это к вашему контролю:

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

Редактировать: версия VM

Я вставил elipsis (...), где я не вносил изменения в ваш код.

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

Так что здесь происходит, когда вы изменяете значение счетчика, вы устанавливаете свойство ButtonIsEnabled, которое вызывает событие изменения свойства и обновляет кнопку в форме с помощью любой логики, которую вы используете, чтобы определить, должна ли кнопка быть включена.

Редактировать: Вам может понадобиться удалить этот Binding=OneWay из текстового поля, я не уверен, будет ли оно инициировать заданное свойство, если вы используете этот параметр.

Если вы хотите сделать это непосредственно в XAML (я не обязательно рекомендую это, так как проверка, вероятно, должна быть выполнена в модели представления), вы также можете использовать пакет, такой как https://quickconverter.codeplex.com/ - это позволяет вам написать C# (ish) в привязке.

Я использовал его раньше, и это может сделать это довольно легко, например, вы устанавливаете пакет, добавляете строку в самом начале вашего приложения:

QuickConverter.EquationTokenizer.AddNamespace(typeof(object));

который добавляет пространство имен System в QuickConverter (строка выше работает как объект в пространстве имен System), а затем вы можете просто сделать:

IsEnabled="{qc:Binding 'Int32.TryParse($P) &amp;&amp; Int32.Parse($P) &gt;= 3', P={Binding ElementName=tbCounter, Path=Text}}"

Если &amp; нарушает ваш Intellisense, вместо этого вы можете написать:

IsEnabled="{qc:Binding 'Int32.TryParse($P) ## Int32.Parse($P) &gt;= 3', P={Binding ElementName=tbCounter, Path=Text}}"

(Куда 3 это значение, с которым вы тестируете).

РЕДАКТИРОВАТЬ:

Извините, перечитывая ваш XAML, он может быть написан еще проще:

IsEnabled="{qc:Binding '$P &gt;= 3', P={Binding CalcViewModel.Counter}}"

Вы должны изменить свою ViewModel на что-то вроде этого

 public class  ViewModel:INotifyPropertyChanged  

        {
        public  int Counter
        {
            get { return _counter;  }
            set {
                _counter = value; 
                 RaisePropChanged("Counter");
                //for example 
                if (value>3)
                {
                    IsButtonCounterEnabled = true;  
                }
                else
                {
                    IsButtonCounterEnabled = false;  


                }
            }
        }
        public bool IsButtonCounterEnabled
        {
            get { return _IsButtonCounterEnabled;   }
            set { _IsButtonCounterEnabled = value;  
                  RaisePropChanged("IsButtonCounterEnabled");
                }
        }
        private  void RaisePropChanged(string propName)
        {
            PropertyChanged(this,new PropertyChangedEventArgs(propName));   

        }


            public event PropertyChangedEventHandler PropertyChanged = delegate{};
            private int _counter;
            private bool _IsButtonCounterEnabled;
}

а затем привязать свою кнопку, как это

 <Button    IsEnabled="{Binding IsButtonCounterEnabled,Mode=OneWay}" Content="Button" HorizontalAlignment="Left" Height="47" Margin="215,57,0,0" VerticalAlignment="Top" Width="159"/>

Надеюсь это поможет

Другие вопросы по тегам