代码之家  ›  专栏  ›  技术社区  ›  Alex F

从代码访问WPF控件验证规则

  •  16
  • Alex F  · 技术社区  · 14 年前

    XAML:

      <TextBox Name="textboxMin">
          <TextBox.Text>
              <Binding Path="Max">
                  <Binding.ValidationRules>
                      <local:IntValidator/>
                  </Binding.ValidationRules>
              </Binding>
          </TextBox.Text>
      </TextBox>
    

    代码:

    void buttonOK_Click(object sender, RoutedEventArgs e)
    {
        // I need to know here whether textboxMin validation is OK
        // textboxMin. ???
    
        // I need to write something like:
        // if ( textboxMin.Validation.HasErrors )
        //     return;
    }
    

    如果至少有一个对话框控件没有通过验证(在XAML中,使用绑定),那么知道如何禁用OK按钮也是很好的。这样,我就不需要检查代码中的验证状态。

    3 回复  |  直到 14 年前
        1
  •  26
  •   Fredrik Hedblad    14 年前

    Validation.hasserror是一个附加属性,因此您可以像这样检查它的textboxMin

    void buttonOK_Click(object sender, RoutedEventArgs e)
    {
        if (Validation.GetHasError(textboxMin) == true)
             return;
    }
    

    要在代码后面运行TextProperty的所有ValidationRules,可以获取BindingExpression并调用UpdateSource

    BindingExpression be = textboxMin.GetBindingExpression(TextBox.TextProperty);
    be.UpdateSource();
    

    更新

    如果发生任何验证,它将采取一些步骤来实现禁用按钮的绑定。

    首先,确保所有绑定都添加NotifyOnValidationError=“True”。例子

    <TextBox Name="textboxMin">
        <TextBox.Text>
            <Binding Path="Max" NotifyOnValidationError="True">
                <Binding.ValidationRules>
                    <local:IntValidator/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    

    然后我们在窗口中连接一个EventHandler到Validation.Error事件。

    <Window ...
            Validation.Error="Window_Error">
    

    在代码隐藏中,我们在observablecollection中添加和移除验证错误

    public ObservableCollection<ValidationError> ValidationErrors { get; private set; } 
    private void Window_Error(object sender, ValidationErrorEventArgs e)
    {
        if (e.Action == ValidationErrorEventAction.Added)
        {
            ValidationErrors.Add(e.Error);
        }
        else
        {
            ValidationErrors.Remove(e.Error);
        }
    }
    

    然后我们可以将按钮的IsEnabled绑定到ValidationErrors

    <Button ...>
        <Button.Style>
            <Style TargetType="Button">
                <Setter Property="IsEnabled" Value="False"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ValidationErrors.Count}" Value="0">
                        <Setter Property="IsEnabled" Value="True"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
    
        2
  •  6
  •   TalentTuner    12 年前

    在你拿到规则之前你需要先拿到绑定

        Binding b=  BindingOperations.GetBinding(textboxMin,TextBox.TextProperty);
        b.ValidationRules
    

    否则可以使用BindingExpression并检查HasError属性

     BindingExpression be1 = BindingOperations.GetBindingExpression (textboxMin,TextBox.TextProperty);
    
    be1.HasError
    
        3
  •  1
  •   bjhuffine    6 年前

    非常感谢弗雷德里克·赫布拉德的解决方案。它也帮助了我。我也同意卢克·科滕的观点,认为它最好作为一种行为。这样就不会在视图层中混合应用程序逻辑,视图模型也不必担心只需简单地在那里进行双重应用验证。以下是我的行为学版本:

    如Fredrik Hedblad所述,首先确保任何控件验证都具有binding属性NotifyOnValidationError=“True”。

    这是视图逻辑。。。简单得多。。。

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    

    然后就在窗口的开始标签下面

        Height="Auto" Width="Auto">
    <i:Interaction.Behaviors>
        <behavior:ValidationErrorMappingBehavior HasValidationError="{Binding IsInvalid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </i:Interaction.Behaviors
    

    然后对于按钮,像普通的那样绑定命令。我们将使用基本的视图模型绑定原则来使用RelayCommand禁用它。

    <Button x:Name="OKButton" Content="OK" Padding="5,0" MinWidth="70" Height="23"
                    HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5,5,0,0"
                    Command="{Binding OKCommand}"/>
    

    现在,视图模型及其基本属性和命令

        private bool _isInvalid = false;
        public bool IsInvalid
        {
            get { return _isInvalid; }
            set { SetProperty<bool>(value, ref _isInvalid); }
        }
    
        private ICommand _okCommand;
        public ICommand OKCommand
        {
            get
            {
                if (_okCommand == null)
                {
                    _okCommand = new RelayCommand(param => OnOK(), canparam => CanOK());
                }
    
                return _okCommand;
            }
        }
    
        private void OnOK()
        {
            //  this.IsInvalid = false, so we're good... let's just close
            OnCloseRequested();
        }
    
        private bool CanOK()
        {
            return !this.IsInvalid;
        }
    

    现在,行为

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Interactivity;
    
    namespace UI.Behavior
    {
    public class ValidationErrorMappingBehavior : Behavior<Window>
    {
        #region Properties
    
        public static readonly DependencyProperty ValidationErrorsProperty = DependencyProperty.Register("ValidationErrors", typeof(ObservableCollection<ValidationError>), typeof(ValidationErrorMappingBehavior), new PropertyMetadata(new ObservableCollection<ValidationError>()));
    
        public ObservableCollection<ValidationError> ValidationErrors
        {
            get { return (ObservableCollection<ValidationError>)this.GetValue(ValidationErrorsProperty); }
            set { this.SetValue(ValidationErrorsProperty, value); }
        }
    
        public static readonly DependencyProperty HasValidationErrorProperty = DependencyProperty.Register("HasValidationError", typeof(bool), typeof(ValidationErrorMappingBehavior), new PropertyMetadata(false));
    
        public bool HasValidationError
        {
            get { return (bool)this.GetValue(HasValidationErrorProperty); }
            set { this.SetValue(HasValidationErrorProperty, value); }
        }
    
        #endregion
    
        #region Constructors
    
        public ValidationErrorMappingBehavior()
            : base()
        { }
    
        #endregion
    
        #region Events & Event Methods
    
        private void Validation_Error(object sender, ValidationErrorEventArgs e)
        {
            if (e.Action == ValidationErrorEventAction.Added)
            {
                this.ValidationErrors.Add(e.Error);
            }
            else
            {
                this.ValidationErrors.Remove(e.Error);
            }
    
            this.HasValidationError = this.ValidationErrors.Count > 0;
        }
    
        #endregion
    
        #region Support Methods
    
        protected override void OnAttached()
        {
            base.OnAttached();
            Validation.AddErrorHandler(this.AssociatedObject, Validation_Error);
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
            Validation.RemoveErrorHandler(this.AssociatedObject, Validation_Error);
        }
    
        #endregion
      }
    }