【问题标题】:Change enabled property of a WPF control (button) based on textbox content根据文本框内容更改 WPF 控件(按钮)的启用属性
【发布时间】:2014-11-05 13:05:19
【问题描述】:

我正在 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">

是否有一种通用方法可以根据 XAML 或 ViewModel 中的属性/值设置控件的 IsEnabled 属性?

编辑这是我的 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));
        }
    }

【问题讨论】:

    标签: c# wpf controls isenabled


    【解决方案1】:

    你想组合一个元素属性绑定:

    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>
    

    编辑:虚拟机版本

    我在没有对您的代码进行更改的地方添加了省略号 (...)。

    <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,如果您使用该设置,我不确定它是否会启动 set 属性。

    【讨论】:

    • @C Bauer:非常感谢。如果您能给我有关 VM 实现的提示,那就太好了。我添加了相关部分,我希望我没有遗漏任何内容或有错字。整个班级都可以在这里发布。
    • @ck84vi 好了。我在底部添加了对它的不同之处的解释。
    • @C Bauer:非常感谢!
    • 如果您有任何其他问题,请随时发表评论。
    • 是的,我有:-)。它工作正常。但问题是我必须单击应用程序中的任何其他控件才能使 Button 在视觉上再次升起。因为如果启用或禁用按钮,我会更改样式。属性设置正确,所以我可以点击其他任何地方,此时我的按钮再次“升起”。因此,一旦按钮的 IsEnabled 被触发,我需要对按钮样式进行某种刷新。有没有办法做到这一点?
    【解决方案2】:

    如果您希望直接在 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;amp; 破坏了您的智能感知,您可以改为:

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

    【讨论】:

    • Edy:我认为你是对的,考虑到验证,我认为在 VM 中进行验证肯定更好。
    • 作为上述的替代方案,您可以简单地为CanExecute_calc.Counter &gt; 3 且运行为ResetCounter.Execute() 的按钮添加不同的ICommand,参见:blogs.msdn.com/b/mikehillberg/archive/2009/03/20/… ICommand 接口如果 CanExecute 方法返回 false,则智能禁用按钮。
    • 这些,看起来很有趣。我也会试试这个
    【解决方案3】:

    你应该把你的 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"/>
    

    希望对你有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-19
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-11
      • 1970-01-01
      • 2011-09-22
      相关资源
      最近更新 更多