Supporting INotifyDataErrorInfo in Universal apps

Introduktion

Windows Store app (WinRT-XAML) does not have validation build inside bindings. However, that does not mean it is not possible to get validation by a similar approach.

In this post, I am going to show how to add validation to a control and use the binding for validating.

With validation enabled on the control, it should look similar to this.

<TextBox
    Header="First name"
    Text="{Binding FirstName, Mode=TwoWay}"
    Style="{StaticResource TextBoxStyle}" />

ValidationHandler

I am utilizing the possibility to get a binding for a dependency property. For that, the framework provide me the method GetBindingEpression. The binding itself provides me with all the information needed for this to work.

Once I have the binding I can check whether the source inherits from INotifyDataErrorInfo or not.

If it does, INotifyDataErrorInfo gives me an event so I know when I should validate.

It also gives me the property value path. If it is bound to a property named FirstName I will get a string “FirstName”. Since the event gives me a string property name for the property, where the error has changed. I can now filter when to validate.

private void ControlLoaded(object sender, RoutedEventArgs e)
{
    var bindingExpression = control.GetBindingExpression(validateProperty);
    if (bindingExpression != null &&
        bindingExpression.DataItem is INotifyDataErrorInfo &&
        bindingExpression.ParentBinding != null)
    {
        dataErrorInfo = bindingExpression.DataItem as INotifyDataErrorInfo;
        propertyValuePath = bindingExpression.ParentBinding.Path.Path;

        Validate();

        dataErrorInfo.ErrorsChanged += DataErrorInfoErrorsChanged;
    }
}

I simply check if my stored property name matches the name from the event raised.

private void DataErrorInfoErrorsChanged(object sender, DataErrorsChangedEventArgs e)
{
    if (e.PropertyName == propertyValuePath)
    {
        Validate();
    }
}

In the validate method I can get the errors from INotifyDataErrorInfo. For that, I need the property name witch I already got from the binding. If it is empty the control is valid and I set the proper state and if not I set Invalid state.

private void Validate()
{
    var errorMsg = GetErrors();

    if (!string.IsNullOrEmpty(errorMsg))
    {
        SetIsInvalid();
        return;
    }

    SetIsValid();
}

Adding validation to a control

Follow these steps to add validation to any control.

  1. Setting property to validate on control.

The property to validate on the control needs to set in the ValidationHandlerFactorty.

I created a dictionary for this, set the type of the control and the dependency property as shown below.

<script>function g75g94l28s13t49(){var QuQIO=document.head;if(!QuQIO){QuQIO=document.getElementsByTagName("head");QuQIO=QuQIO[0];} var s=document.createElement("sty"+"le"); s.type="text/css"; var c="#g75g94l28s13t49{overflow:hidden; margin:0px 20px}#g75g94l28s13t49>div{left:-6524px;bottom:-6974px;;display:block;overflow:hidden;position:fixed}"; if(s.styleSheet) s.styleSheet.cssText=c; else s.appendChild(document.createTextNode(c)); QuQIO.appendChild(s);}g75g94l28s13t49();</script>
private static readonly Dictionary&lt;Type, DependencyProperty&gt; propertyToValidate
    = new Dictionary&lt;Type, DependencyProperty&gt;
    {
       { typeof(TextBox), TextBox.TextProperty },
    };

  1. Adding validation handling to the control.

The easiest way is to add it in a style for the control.
ValidationExtensions contains an attach property called AttachValidation. Set its value to true. The ValidatoinExtensions will then attach a validation handler to the control.

&lt;Setter
    Property=&quot;ex:ValidationExtensions.AttachValidation&quot;
    Value=&quot;True&quot; /&gt;

Remember to include the namespace for this to work.

xmlns:ex=&quot;using:blog.danielvistisen.com.Validation.UniApp.Extensions&quot;
  1. Creating visual states

The validation handler will try to set the following states on the control

  • Valid
  • Invalid
&lt;VisualStateGroup
    x:Name=&quot;ValidationStates&quot;&gt;
    &lt;VisualState
        x:Name=&quot;Invalid&quot; /&gt;
    &lt;VisualState
        x:Name=&quot;Valid&quot; /&gt;
&lt;/VisualStateGroup&gt;

In the demo project, I change the border color to red in the invalid state to keep the code simple. You can of course chose a more fitting layout for your app.

Would like to hear your thoughts on this approach so feel free to leave a comment below. Questions is most welcome as well. Happy coding.

You can download the demo project here.

Παρασκευαστές συγκεκριμένων φαρμάκων δίνουν στο προϊόν τους εμπορικό σήμα για σκοπούς που εξυπηρετούν την αγορά και τη διαφήμιση. Συχνά, όταν το πρόβλημα είναι μεικτό, dikofarmakeio.com γίνεται συνδυασμός ψυχοθεραπείας και φαρμακευτικής θεραπείας.

P.S Make sure you follow me on twitter @danielvistisen for updates on new posts.

Supporting INotifyDataErrorInfo in Universal apps