I use WPF data binding with entities that implement IDataErrorInfo interface. In general my code looks like this:
Business entity:
p
I believe this behavior to also be a good solution. It removes ErrorTemplate on TextBox when needed and also supports multiple "valid" invalid values (you can also improve it by making ValidInputs a dependency property).
public class NotValidateWhenSpecified : Behavior<TextBox>
{
private ControlTemplate _errorTemplate;
public string[] ValidInputs { get; set; } = { string.Empty };
protected override void OnAttached()
{
AssociatedObject.TextChanged += HideValiationIfNecessary;
_errorTemplate = Validation.GetErrorTemplate(AssociatedObject);
Validation.SetErrorTemplate(AssociatedObject, null);
}
protected override void OnDetaching()
{
AssociatedObject.TextChanged -= HideValiationIfNecessary;
}
private void HideValiationIfNecessary(object sender, TextChangedEventArgs e)
{
if (ValidInputs.Contains(AssociatedObject.Text))
{
if (_errorTemplate != null)
{
_errorTemplate = Validation.GetErrorTemplate(AssociatedObject);
Validation.SetErrorTemplate(AssociatedObject, null);
}
}
else
{
if (Validation.GetErrorTemplate(AssociatedObject) != _errorTemplate)
{
Validation.SetErrorTemplate(AssociatedObject, _errorTemplate);
}
}
}
}
I've implemented the following solution:
public class SkipValidationOnFirstLoadBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
AssociatedObject.LostFocus += AssociatedObjectOnLostFocus;
}
private void AssociatedObjectOnLostFocus(object sender, RoutedEventArgs routedEventArgs)
{
//Execute only once
AssociatedObject.LostFocus -= AssociatedObjectOnLostFocus;
//Get the current binding
BindingExpression expression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
if (expression == null) return;
Binding parentBinding = expression.ParentBinding;
//Create a new one and trigger the validation
Binding updated = new Binding(parentBinding.Path.Path);
updated.ValidatesOnDataErrors = true;
updated.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
AssociatedObject.SetBinding(TextBox.TextProperty, updated);
}
}
Example of usage:
<TextBox Text="{Binding Email}">
<i:Interaction.Behaviors>
<local:SkipValidationOnFirstLoadBehavior/>
</i:Interaction.Behaviors>
</TextBox>