C# – Show Validation Error Template on Controls within a UserControl in WPF

cidataerrorinfomvvmvalidationwpf

How do you get the WPF error template to appear on a control within a UserControl in WPF?

I have a UserControl containing two Labels, two TextBoxes, and a CheckBox. One of the TextBoxes represents the name of the entity and it is bound to a Name property off of a Model property exposed by my ViewModel, which is the DataContext of my Window. The Model class implements the IDataErrorInfo interface and I have confirmed through Unit Testing that when the Name is blank an error is returned through the property indexer implementation. I have bound to the Dependency Property backing the Name TextBox in my UserControl and when the validation error is encountered the WPF error template places a red border around the entire UserControl rather than just the Name TextBox.

The binding to the name field of the UserControl is as follows.

<vc:MyUserControl ItemName="{Binding Model.Name, ValidatesOnDataErrors=True}" />

A simiplified version of my UserControl and the backing DependencyProperty is as follows.

<UserControl>
    <Grid>
       <TextBox Text="{Binding ItemName}" />
    </Grid>
</UserControl>

public partial class MyUserControl: UserControl
{
    public static readonly DependencyProperty ItemNameProperty = 
        DependencyProperty.Register(
            "ItemName", 
            typeof(string), 
            typeof(MyUserControl), 
            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
    );

    public string ItemName
    {
        get { return (string)GetValue(ItemNameProperty); }
        set { SetValue(ItemNameProperty, value); }
    }
}

The information I have found relating to this issue thus far has all been in regards to Silverlight or using a converter to not show the red border (which did not make sense to me). This information was all found here on stackoverflow.

Has anyone been able to solve this issue with WPF? Am I overlooking something obvious?

Best Answer

The ErrorTemplate for UserControl will be used if bindings to your UserControl use ValidatesOnDataErrors=True. But you can remove the red border with the Validation.ErrorTemplate Attached Property.

All controls within your UserControl will only show a red border if you validate their bindings by implementing IDataErrorInfo for the backing DependencyProperties too.

public class MyUserControl : UserControl, IDataErrorInfo
{
   public static readonly DependencyProperty ItemNameProperty =
       DependencyProperty.Register(
           "ItemName",
           typeof(string),
           typeof(MyUserControl),
           new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
   );

   public string ItemName
   {
      get { return (string)GetValue(ItemNameProperty); }
      set { SetValue(ItemNameProperty, value); }
   }

   public string Error
   {
      get { throw new NotImplementedException(); }
   }

   public string this[string columnName]
   {
      get
      {
         // use a specific validation or ask for UserControl Validation Error 
         return Validation.GetHasError(this) ? "UserControl has Error" : null;
      }
   }
}

and here the simplified XAML

<UserControl Validation.ErrorTemplate="{x:Null}">
   <Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
      <TextBox Text="{Binding ItemName, ValidatesOnDataErrors=True}" />
   </Grid>
</UserControl>

Addition

If you want to differentiate between errors you can get the BindingExpression for your DependencyProperty and check the HasError Property.

BindingExpression be = BindingOperations.GetBindingExpression(this, ItemNameProperty);
return be != null && be.HasError ? "ItemName has Error" : null;
Related Topic