Wpf – Accessing WPF control validation rules from code

bindingvalidationwpf

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)
{
    // I need to know here whether textboxMin validation is OK
    // textboxMin. ???

    // I need to write something like:
    // if ( textboxMin.Validation.HasErrors )
    //     return;
}

It would be nice also to know, how to disable OK button, if at least one of dialog controls doesn't pass validation – in XAML, using binding. Having this way, I don't need to check validation state in the code.

Best Answer

Validation.HasError is an attached property so you can check it for textboxMin like this

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

To run all ValidationRules for the TextProperty in code behind you can get the BindingExpression and call UpdateSource

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

Update

It will take some steps to achieve the binding to disable the button if any validation occurs.

First, make sure all bindings add NotifyOnValidationError="True". Example

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

Then we hook up an EventHandler to the Validation.Error event in the Window.

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

And in code behind we add and remove the validation errors in an observablecollection as they come and go

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

And then we can bind IsEnabled of the Button to ValidationErrors.Count like this

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