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

21

XAML:

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

Code:

void buttonOK_Click(object sender, RoutedEventArgs e)
{
    // 我需要在这里知道textboxMin的验证是否通过
    // textboxMin. ???
// 我需要编写以下代码: // if ( textboxMin.Validation.HasErrors ) // return; }

如果至少有一个对话框控件未通过验证,通过绑定在XAML中禁用OK按钮会很好。这样一来,我就不需要在代码中检查验证状态了。


您需要知道特定的ValidationRule是否有错误,还是只需要知道TextBox是否有错误? - Fredrik Hedblad
3个回答

30

Validation.HasError是一个附加属性,因此您可以像这样检查textboxMin是否有错误:

Validation.HasError是一個可附加的屬性,所以您可以像這樣檢查是否有錯誤:

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

然后我们可以像这样将按钮的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>

第一个版本 - Validation.HasError没有编译。编辑后,GetHasError正常工作并给出了预期的结果。谢谢。 - Alex F
最好使用AttachedProperty或Behavior来实现此目的,但感谢提到NotifyOnValidationError必须设置为true! - Lukáš Koten

8

在获取规则之前,您需要先获取绑定。

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

否则,您可以使用BindingExpression并检查HasError属性。
 BindingExpression be1 = BindingOperations.GetBindingExpression (textboxMin,TextBox.TextProperty);

be1.HasError

1
BindingOperations.GetBindingExpression(textBoxMin, TextBox.TextProperty).HasError 做到了这一点。 - Alex F

1
非常感谢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
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接