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

时间:2010-11-25 06:32:56

标签: wpf validation binding

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

如果至少有一个对话框控件没有通过验证,那么如何知道如何禁用OK按钮会更好 - 在XAML中,使用绑定。有了这种方式,我不需要在代码中检查验证状态。

3 个答案:

答案 0 :(得分:24)

Validation.HasError是一个附加属性,因此你可以像这样检查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挂钩到Window中的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);
    }
}

然后我们可以将Button的IsEnabled绑定到ValidationErrors.Count,就像这样

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

答案 1 :(得分:6)

在获得规则之前,你需要先获得Binding

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

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

 BindingExpression be1 = BindingOperations.GetBindingExpression (textboxMin,TextBox.TextProperty);

be1.HasError

答案 2 :(得分:0)

非常感谢Fredrik Hedblad的解决方案。它也帮助了我。我同意LukášKoten的说法,它最适合用作行为。这样,视图层中不会混合使用混合的应用程序逻辑,并且视图模型不必担心复制验证只是为了简单地将其放在那里。这是我的行为版本:

正如Fredrik Hedblad所说,首先要确保任何控件验证都具有绑定属性NotifyOnValidationError =“True”。

这是视图逻辑......更简单......

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

然后在Window开始标记

下面
    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
  }
}