Show Validation Error in UserControl

I am not sure why the validation state doesn't get reflected in my user control. I am throwing an exception but for some reason the control doesn't show the validation state...When I use a standard Textbox (Which is commented out right now in my example) on my MainPage it shows the error state, not sure why its not when its wrapped.

I have slimmed this down so basically its a user control that wraps a TextBox. What am I missing??

MyUserControl XAML:

<UserControl x:Class="ValidationWithUserControl.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox x:Name="TextBox"/>
    </Grid>
</UserControl>

MyUserControl Code Behind:

public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MyUserControl_Loaded);
        this.TextBox.Unloaded += new RoutedEventHandler(TextBox_Unloaded);
    }

    public string Value
    {
        get { return (string)base.GetValue(ValueProperty); }
        set { base.SetValue(ValueProperty, value); }
    }

    public static DependencyProperty ValueProperty =
        DependencyProperty.Register(
        "Value",
        typeof(string),
        typeof(MyUserControl),
        new PropertyMetadata(null));

    private void MyUserControl_Loaded(object sender, RoutedEventArgs e)
    {
        this.TextBox.SetBinding(TextBox.TextProperty, new Binding()
        {
            Source = this,
            Path = new PropertyPath("Value"),
            Mode = BindingMode.TwoWay,
            ValidatesOnExceptions = true,
            NotifyOnValidationError= true
        });  
    }

    private void TextBox_Unloaded(object sender, RoutedEventArgs e)
    {
        this.TextBox.ClearValue(TextBox.TextProperty);
    }
}

My MainPage XAML:

<Grid x:Name="LayoutRoot" Background="LightBlue">
    <StackPanel>
        <uc:MyUserControl x:Name="UC" Value="{Binding Path=Value, Mode=TwoWay}" Height="20" Width="100" />
        <!--TextBox x:Name="MS" Text="{Binding Path=Value, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" Height="20" Width="100" /-->
    </StackPanel>
</Grid>

My MainPage Code Behind:

public partial class MainPage : UserControl
{
    private Model model;
    //private Model model2;

    public MainPage()
    {
        InitializeComponent();
        this.model = new Model("UC");
        //this.model2 = new Model("MS");
        this.UC.DataContext = this.model;
        //this.MS.DataContext = this.model2;
    }
}

My Model:

public class Model
{
    public Model(string answer)
    {
        this.answer = answer;
    }

    private string answer;
    public string Value
    {
        get
        {
            return this.answer;
        }
        set
        {
            if (!String.IsNullOrEmpty(value))
                this.answer = value;
            else
                throw new Exception("Error");
        }
    }
}

Ok, I finally figured out how to handle this.

What you need to do here is to copy the validation from the original binding and send it to the Textbox binding.

The first thing you'll need to do to achieve this is to implement the INotifyDataErrorInfo interface in your user control. Then you'll have to validate the user control to get the exact validation text withon the GetErrors function (This can be done with the Validation.GetErrors).

This is a basic implementation and it's in VB but I'm sure you get the point.

    Public Event ErrorsChanged(ByVal sender As Object, ByVal e As System.ComponentModel.DataErrorsChangedEventArgs) Implements System.ComponentModel.INotifyDataErrorInfo.ErrorsChanged

Public Function GetErrors(ByVal propertyName As String) As System.Collections.IEnumerable Implements System.ComponentModel.INotifyDataErrorInfo.GetErrors
    Dim returnValue As System.Collections.IEnumerable = Nothing

    Dim errorMessage As String = Nothing


    If propertyName = "Value" Then

        If Validation.GetErrors(Me).Count = 0 Then
            errorMessage = ""
        Else
            errorMessage = Validation.GetErrors(Me).First.ErrorContent.ToString
        End If

        If String.IsNullOrEmpty(errorMessage) Then
            returnValue = Nothing
        Else
            returnValue = New List(Of String)() From {errorMessage}
        End If

    End If

    Return returnValue

End Function

Public ReadOnly Property HasErrors As Boolean Implements System.ComponentModel.INotifyDataErrorInfo.HasErrors
    Get
        Return Validation.GetErrors(Me).Any()
    End Get
End Property

The next thing to do is to notify you control it becomes invalid. You will have to do this in 2 places.

The first one will be on the BindingValidationError event. The second one will be in the Value PropertyChangedCallback function (It has to be specified when you register the DependencyProperty)

Public Shared ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(String), GetType(XDateTimePicker), New PropertyMetadata(Nothing, AddressOf ValuePropertyChangedCallback))

Public Shared Sub ValuePropertyChangedCallback(ByVal dependencyObject As DependencyObject, ByVal dependencyPropertyChangedEventArgs As DependencyPropertyChangedEventArgs)
    DirectCast(dependencyObject, MyUserControl).NotifyErrorsChanged("Value")
End Sub

Private Sub MyUserControl_BindingValidationError(ByVal sender As Object, ByVal e As System.Windows.Controls.ValidationErrorEventArgs) Handles Me.BindingValidationError
    Me.NotifyErrorsChanged("Value")
End Sub

Public Sub NotifyErrorsChanged(ByVal propertyName As String)
    RaiseEvent ErrorsChanged(Me, New System.ComponentModel.DataErrorsChangedEventArgs(propertyName))
End Sub

Most of the job is done now but you still need to make some adjustments to the bindings.

When you create the TextBox binding, you need to set the NotifyOnValidationError to False to avoid a notifications loop between the original binding and the Textbox binding. ValidatesOnExceptions, ValidatesOnDataErrors and ValidatesOnNotifyDataErrors need to be set to True.

        Dim binding As New System.Windows.Data.Binding

    binding.Source = Me
    binding.Path = New System.Windows.PropertyPath("Value")
    binding.Mode = Data.BindingMode.TwoWay
    binding.NotifyOnValidationError = False 
    binding.ValidatesOnExceptions = True
    binding.ValidatesOnDataErrors = True
    binding.ValidatesOnNotifyDataErrors = True

    Me.TextBox1.SetBinding(TextBox.TextProperty, binding)

Finaly, you need to set the NotifyOnValidationError and ValidatesOnNotifyDataErrors property to True in your XAML.

<uc:MyUserControl x:Name="UC" Value="{Binding Path=Value, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnNotifyDataErrors=True}" Height="20" Width="100" />

How to show Validation Error Message for UserControls in UI for , I'm using a UserControl to show and edit a specific property in RadPropertyGrid. In the setter of the property I throw a ValidationException if the  Notice in the validation control template, we are using a DockPanel as the layout control, therefore we can easily change where the error icon and error message will be displayed. We can display them on top of the control that is failing validation (as the above picture), or on the left, right, or bottom.

This behaviour is caused by an added binding level. Bindings do not support forwarding validation errors.

What happens behind the scenes:

  1. User inputs text into TextBox, and the binding defined in MyUserControl_Loaded passes the value to the MyUserControl.ValueProperty.
  2. Next, the binding defined in MainPage XAML for MyUserControl passes the value to the Model.
  3. An Exception thrown in Model.Value.set() is handled by the binding that has been set up in MainPage XAML.
  4. No exception is passed forward to the binding associated with a TextBox.
  5. Since UserControl does not have ValidatesOnExceptions set on true, no visual indication is displayed.

To resolve this issue you could bind the text box directly to the Model like this:

this.TextBox.SetBinding(TextBox.TextProperty, new Binding()
{
    Source = this.DataContext, // bind to the originating source
    Path = new PropertyPath("Value"),
    Mode = BindingMode.TwoWay,
    ValidatesOnExceptions = true,
    NotifyOnValidationError= true
});  

Since 6 months have passed I wonder if and how did you overcome this problem.

How to forward Validation Errors from elements of a UserControl to , In XAML, some ValidationRules are bound to the TextBox. If the TextBox contains invalid data, a red frame is shown, and the tooltip is set to the error description. Hi Kim, You can add a dependency property in the UserControl and bind this DP to "<Binding RelativeSource="{RelativeSource Self}" Path="(Validation

You should be able to echo the dependency property binding directly to the usercontrol textbox. This will pick up validation errors the same way bindings in the parent view would. In your MyUserControl_Loaded function:

var valueBinding = BindingOperations.GetBindingBase(this, ValueProperty);
if (valueBinding != null) TextBox.SetBinding(TextBox.TextProperty, valueBinding);

T828877, Hi Team, I have a user control with TextEdit and flyout control. There is validation implemented for textedit in mainwindow viewmodel. for. By extending ContainerControl, UserControl inherits all the standard positioning and mnemonic-handling code that is necessary in a user control. The UserControl gives you the ability to create controls that can be used in multiple places within an application or organization.

If somebody comes around looking for a good (read: "not written in VBA and complete") solution for this problem, I wrote a base class (although i've tested it only with lookless controls, do not know if it works with UserControls) based on @The_Black_Smurf's answer in C#:

namespace MyApplication.Controls
{
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;

    public abstract class ControlBaseWithValidation : Control, INotifyDataErrorInfo
    {
        public ControlBaseWithValidation()
        {
            // remove the red border that wraps the whole control by default
            Validation.SetErrorTemplate(this, null);
        }

        public delegate void ErrorsChangedEventHandler(object sender, DataErrorsChangedEventArgs e);

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public bool HasErrors
        {
            get
            {
                var validationErrors = Validation.GetErrors(this);
                return validationErrors.Any();
            }
        }

        public IEnumerable GetErrors(string propertyName)
        {
            var validationErrors = Validation.GetErrors(this);
            var specificValidationErrors =
                validationErrors.Where(
                    error => ((BindingExpression)error.BindingInError).TargetProperty.Name == propertyName).ToList();
            var specificValidationErrorMessages = specificValidationErrors.Select(valError => valError.ErrorContent);
            return specificValidationErrorMessages;
        }

        public void NotifyErrorsChanged(string propertyName)
        {
            if (ErrorsChanged != null)
            {
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
            }
        }

        protected static void ValidatePropertyWhenChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            ((ControlBaseWithValidation)dependencyObject).NotifyErrorsChanged(dependencyPropertyChangedEventArgs.Property.Name);
        }
    }
}

use ControlBaseWithValidation class as a base class for your lookless controls instead of the Control class and add ValidatePropertyWhenChangedCallbackcallback as the PropertyChangedCallback on any Dependency properties that you want to validate.

How do I show error message for controls in usercontrol in WPF, Validation works for in 1st tab. But in user control, validation works and red border shows around the control but didn't show the error message. Adding validation rules to controls in a form template ensures that the data collected is accurate and consistent. When you add a text control, users can type anything into it.

Process Validation Error in a UerControl - MSDN, I have a reusable UserControl with several input textbox fields to collect address info. I'm able to bind the user control and validate the entity  There are two sources of validation errors: Validation errors detected by the framework including data conversion errors and validation rules registered with the view. User validation code in the view-model - in which case, the user code can directly add or remove validation errors from the collection.

Creating WPF TextBox UserControl to Perform Custom Validation, In this article we are going to implement a user control which will validate a TextBox based on The Label will be used to display the error message to the user.

SL35: Using the Validation and ValidationSummary APIs to , The example shown in this technique uses both ValidationSummary and Validation.Errors . Example 1: Two form fields with validation on Submit, and an error 

Comments
  • This helped me a lot. Thanks!
  • I am having the same problem and I am following your answer to solve it, but it does not work for me. What am I missing? This is my question.
  • Oops forgot to link to my asked question, if you have time to check it out - stackoverflow.com/questions/7349627/…
  • @SimonBesner Did you figure out how to do it when you have multiple controls inside your UserControl? I'd like to show red border around whole UserControl..
  • If you only need a red border around the whole control, then you only have to use the last snippet: <uc:MyUserControl x:Name="UC" Value="{Binding Path=Value, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnNotifyDataErrors=True}" Height="20" Width="100" />
  • This would work in this particular case but you wont be able to reuse same user control for different model (or data context) binded on a property name different than "Value".
  • Good point. How about exposing the entire TextBox as a public property? Or implement INofifyPropertyChanged on TextBox.Changed event (to remove the double-binding)
  • I wonder what would happen if you handled the binding error event in your user control and rethrow an exception there. I'll try this later.
  • This works for me, but I also need to set the Validation ErrorTemplate of the user control to null: Validation.ErrorTemplate={x:Null} in XAML or Validation.SetErrorTemplate(this, null); in code-behind.