Intersoft ClientUI Documentation
Walkthrough: Clear Validation Error on Text Input using ClearErrorOnTextInput

This walkthrough shows how to display book details information and show an error alert when the book's textbox field is empty, also how to implement ClearErrorOnTextInput which make the error alert directly disappear when user type in the textbox using MVVM pattern.

In this walkthrough, you perform the following tasks:

Prerequisites

You need the following components to complete this walkthrough:

Creating a new ClientUI MVVM Application Project

The first step is to create a new ClientUI MVVM Application project using Intersoft ClientUI MVVM Application project template in Visual Studio.

To create the ClientUI MVVM Application project

  1. Start Visual Studio 2010.
  2. Create a new ClientUI MVVM Application project using Intersoft ClientUI MVVM Application project template. To learn more, see Walkthrough: Create New Intersoft ClientUI MVVM Application Template.

Next, you will create the Book model class that represent the data entity used in this walkthrough.

Creating Model Class

This section shows how to create the Book model class that represents the data entity used in this walkthrough.

To create the Book Model Class

  1. Create a model class that inherits from ModelBase class under the Models folder, named it Book.cs.
  2. Add ID property to the Book model class. by defining the backing field along with complete getter and setter in the property. In the setter property, you need to call the OnPropertyChanged method after the backing field is assigned to the new value 
    C#
    Copy Code
    private string _ID;
    
    public string ID
    {
        get
        {
            return _ID;
        }
        set
        {
            if (_ID != value)
            {
                _ID = value;
                OnPropertyChanged("ID");
            }
        }
    }
  3. Also add Author, Title and Category property to the Book model class by repeating step number 2.
    C#
    Copy Code
    private string _author;
    private string _title;
    private string _category;
    
    public string Author
    {
        get
        {
            return _author;
        }
        set
        {
            if (_author != value)
            {
                _author = value;
                OnPropertyChanged("Author");
            }
        }
    }
    
    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            if (_title != value)
            {
                _title = value;
                OnPropertyChanged("Title");
            }
        }
    }
    
    public string Category
    {
        get
        {
            return _category;
        }
        set
        {
            if (_category != value)
            {
                _category = value;
                OnPropertyChanged("Category");
            }
        }
    }
  4. Add Price property to Book model.
    C#
    Copy Code
    private double _price;
    public double Price
    {
        get
        {
            return _price;
        }
        set
        {
            if (_price != value)
            {
                _price = value;
                OnPropertyChanged("Price");
            }
        }
    }
  5. Add EnableValidation property to Book model.
    C#
    Copy Code
    public bool EnableValidation { get; set; }
  6. Add validation checking for Author, Title and Price property.
    C#
    Copy Code
    public string Author
    {
        get
        {
            return _author;
        }
        set
        {
            if (_author != value)
            {
                _author = value;
                ClearError("Author");
                OnPropertyChanged("Author");
            }
        }
    }
    
    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            if (_title != value)
            {
                _title = value;
                ClearError("Title");
    
                if (EnableValidation && string.IsNullOrEmpty(this.Title))
                    SetError("Title", "Title is required");
    
                OnPropertyChanged("Title");
            }
        }
    }
    
    public double Price
    {
        get
        {
            return _price;
        }
        set
        {
            if (_price != value)
            {
                _price = value;
                ClearError("Price");
    
                if (EnableValidation && (double.IsNaN(this.Price) || this.Price == 0.0))
                    SetError("Price", "Price is required");
    
                OnPropertyChanged("Price");
            }
        }
    }
  7. Add Book model constructor.
    C#
    Copy Code
    public Book()
    {
    }

Creating the View

This section steps you through the process of creating a page that uses a variety of ClientUI controls such as UXItemsControl, FieldLabel, and StylishLabel.

To create the View

  1. Right click on Views folder, and add new item. Select Intersoft UXPage as the template page. Name it ShowBookInformation.xaml then click Add.
  2. Double click on Book.xaml and add UXItemsControl. Set the following properties:
    Property Value
    Height 110
    Width 250
    HorizontalAlignment Center
    VerticalAlignment Center
    Background White
    CornerRadius 8
    Padding 0,0,0,10
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Intersoft:UXItemsControl Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
                
        </Intersoft:UXItemsControl>
    </Grid>
  3. Add StylishLabel inside the UXItemsControls. Set Content to Book Details, CornerRadius to 8,8,0,0 and Margin to 0,0,0,10.
    XAML
    Copy Code
    <Intersoft:UXItemsControl Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
        <Intersoft:StylishLabel Content="Book Details" CornerRadius="8,8,0,0" Margin="0,0,0,10"/>
    </Intersoft:UXItemsControl>

  4. Add Intersoft FieldLabel control after StylishLabel. Set the Header property to Title:, HeaderWidth to 80 and HorizontalHeaderAlignment to Right. Also set the HorizontalAlignment of UXTextBox to Center and its Width to 132.
    XAML
    Copy Code
    <Intersoft:UXItemsControl Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
        <Intersoft:StylishLabel Content="Book Details" CornerRadius="8,8,0,0" Margin="0,0,0,10"/>
        <Intersoft:FieldLabel Header="Title:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="132"/>
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>

  5. Add another FieldLabel control and set the Header to Price, HeaderWidth to 80 and HorizontalHeaderAlignment to Right. Also set HorizontalAlignment of UXTextBox to Center and Width to 60.
    XAML
    Copy Code
    <Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
        <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60"/>
    </Intersoft:FieldLabel>

  6. Set the LayoutRoot Background to Black.
    XAML
    Copy Code
    ...
    <Grid x:Name="LayoutRoot" Background="Black">
    ...

Creating the ViewModel Pattern

This section steps you through the process of creating a ViewModel class that contains the properties to describe the View that you created in the previous section. Also in this step, you will create a validation class for the property validation.

To create the BookViewModel

  1. Create ValidationViewModelBase class that inherit from ViewModelBase and implement IDataErrorInfo interface. The BookViewModel will inherit this class.
    C#
    Copy Code
    ...
    namespace ClientUIMVVMApp2.ViewModels
    {
        public class ValidationViewModelBase : ViewModelBase, IDataErrorInfo
        {
            #region Properties
    
            private Dictionary<string, string> _errors = new Dictionary<string, string>();
    
            public virtual bool HasErrors
            {
                get
                {
                    return _errors.Count > 0;
                }
            }
    
            #endregion
    
            #region Public
    
            public void SetError(string propertyName, string errorMessage)
            {
                _errors[propertyName] = errorMessage;
                this.OnPropertyChanged(propertyName);
            }
    
            #endregion
    
            #region Protected
    
            protected void ClearError(string propertyName)
            {
                this._errors.Remove(propertyName);
            }
    
            protected void ClearAllErrors()
            {
                List<string> properties = new List<string>();
    
                foreach (KeyValuePair<string, string> error in this._errors)
                    properties.Add(error.Key);
    
                this._errors.Clear();
    
                foreach (string property in properties)
                    this.OnPropertyChanged(property);
            }
    
            #endregion
    
            #region IDataErrorInfo Members
    
            public string Error
            {
                get
                {
                    if (this.HasErrors)
                        return this._errors.First().Value;
    
                    return null;
                }
            }
    
            public string this[string columnName]
            {
                get
                {
                    if (this._errors.ContainsKey(columnName))
                    {
                        return this._errors[columnName];
                    }
                    return string.Empty;
                }
            }
    
            #endregion
        }
    }
    ...
  2. Create new BookViewModel that inherit from ValidationViewModelbase class by add new class to ViewModels folder and named it BookViewModel.cs.
    C#
    Copy Code
    ...
    public class BookViewModel : ValidationViewModelBase
    {
        // Fields
        private Book _book;
    
        // Constructor
        public BookViewModel()
        {
            this.Book = new Book { Title = "Excel 2007 For Dummies", Price = 15.83 };
            this.Book.EnableValidation = true;
        }
    
        // Views
        public Book Book
        {
            get { return this._book; }
            set
            {
                if (this._book != value)
                {
                    this._book = value;
                    OnPropertyChanged("Book");
                }
            }
        }
    
        public string Title
        {
            get { return this.Book.Title; }
        }
    
        public string ShortTitle
        {
            get
            {
                if (this.Book.Title.Length < 80)
                    return this.Title;
                else
                    return this.Book.Title.Substring(0, 80) + "...";
            }
        }
    }
    ...

Binding the View to ViewModel

In the previous sections, you have learned how to create the Model and ViewModel classes, as well as the View that contains the user interface and controls used in this walkthrough.

This section show how to instantiate the ViewModel in the XAML page  and bind the ViewModel that was created in the previous section to the View for example you will bind the Text property of TextBox to Book.Price property of the BookViewModel.

To bind the Book page to the BookViewModel class

  1. Open ShowBookInformation.xaml. Declare the namespace that maps to the BookViewModel class in the ShowBookInformation page. Instantiate a new instance of the BookViewModel class in the UXPage resources and name it BookViewModel.
    XAML
    Copy Code
    ..
    <Intersoft:UXPage 
            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"
        xmlns:ViewModels="clr-namespace:ClientUIMVVMApp2.ViewModels"
            mc:Ignorable="d"
    ..      
    <Intersoft:UXPage.Resources>
        <ViewModels:BookViewModel x:Key="BookViewModel"></ViewModels:BookViewModel>
    </Intersoft:UXPage.Resources>
    ...
  2. Bind the DataContext property of the LayoutRoot to the BookViewModel through the static resource extension markup.
    XAML
    Copy Code
    ...
    <Grid x:Name="LayoutRoot" Background="Black" DataContext="{StaticResource BookViewModel}">
    ...
  3. Bind Book.Title and Book.Price to Title and Price to UXTextBox.
    XAML
    Copy Code
    ...
    <Intersoft:UXItemsControl DataContext="{StaticResource BookViewModel}" Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
        <Intersoft:StylishLabel Content="Book Details" CornerRadius="8,8,0,0" Margin="0,0,0,10"/>
        <Intersoft:FieldLabel Header="Title:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="132" Text="{Binding Book.Title, Mode=TwoWay}"/>
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60" Text="{Binding Book.Price, Mode=TwoWay}"/>
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>
    ...


    If the data does not show, Try to rebuild the project.
  4. Add validation error to Title and Price UXTextBox by set ValidatesOnDataErrors to True in the binding definition.
    XAML
    Copy Code
    ...
    <Intersoft:UXItemsControl DataContext="{StaticResource BookViewModel}" Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
        <Intersoft:StylishLabel Content="Book Details" CornerRadius="8,8,0,0" Margin="0,0,0,10"/>
        <Intersoft:FieldLabel Header="Title:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="132" Text="{Binding Book.Title, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60" Text="{Binding Book.Price, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:c\}}"/>
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>
    ...
  5. Make sure that in App.xaml.cs, the Application StartUp should be set to ShowBookInformation.
    C#
    Copy Code
    ...
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        this.RootVisual = new Views.ShowBookInformation();   
    }
    ...
  6. Save, build and run the project. Try to clear the Title text box and lost focus from the it. An error validation will appear like show in the following screenshot.
  7. Now, let's enhance the error alert that appear. With the current validation, the error alert will disappear when the Title textbox is not empty and user should lost focus from the Title textbox. To make the error alert more interactive, set Intersoft:DataBinding.ClearErrorOnTextInput to True in Title textbox. By setting Intersoft:DataBinding.ClearErrorOnTextInput to True, the error alert will disappear directly when user type in the Title textbox. This can happen because there is an interactive checking when user type into the Title textbox, which from the checking indicate that the condition of error does not meet since Title textbox is not empty anymore.
    XAML
    Copy Code
    ...
    <Intersoft:UXItemsControl DataContext="{StaticResource BookViewModel}" Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
        <Intersoft:StylishLabel Content="Book Details" CornerRadius="8,8,0,0" Margin="0,0,0,10"/>
        <Intersoft:FieldLabel Header="Title:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="132" Text="{Binding Book.Title, Mode=TwoWay, ValidatesOnDataErrors=True}" Intersoft:DataBinding.ClearErrorOnTextInput="True"/>
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
            <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60" Text="{Binding Book.Price, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:c\}}" Intersoft:DataBinding.ClearErrorOnTextInput="True"/>
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>
    ...
    The following screenshot shows that the error alert is disappear then user type in to the Title textbox.

Complete Code Listing

This section lists the complete code used in this walkthrough.

Book.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ClientUIMVVMApp2.ViewModels;
using System.Xml.Linq;

namespace ClientUIMVVMApp2.Models
{
    public class Book : ModelBase
    {
        #region Constructor

        public Book()
        {
        }

        #endregion

        #region Fields

        private string _ID;
        private string _author;
        private string _title;
        private string _category;
        private double _price;

        #endregion

        #region Properties

        public bool EnableValidation { get; set; }

        public string ID
        {
            get
            {
                return _ID;
            }
            set
            {
                if (_ID != value)
                {
                    _ID = value;
                    OnPropertyChanged("ID");
                }
            }
        }

        public string Author
        {
            get
            {
                return _author;
            }
            set
            {
                if (_author != value)
                {
                    _author = value;
                    ClearError("Author");
                    OnPropertyChanged("Author");
                }
            }
        }

        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                if (_title != value)
                {
                    _title = value;
                    ClearError("Title");

                    if (EnableValidation && string.IsNullOrEmpty(this.Title))
                        SetError("Title", "Title is required");

                    OnPropertyChanged("Title");
                }
            }
        }

        public string Category
        {
            get
            {
                return _category;
            }
            set
            {
                if (_category != value)
                {
                    _category = value;
                    OnPropertyChanged("Category");
                }
            }
        }

        public double Price
        {
            get
            {
                return _price;
            }
            set
            {
                if (_price != value)
                {
                    _price = value;
                    ClearError("Price");

                    if (EnableValidation && (double.IsNaN(this.Price) || this.Price == 0.0))
                        SetError("Price", "Price is required");

                    OnPropertyChanged("Price");
                }
            }
        }

        #endregion
    }
}

ShowBookInformation.xaml

XAML
Copy Code
<Intersoft:UXPage 
        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"
    xmlns:ViewModels="clr-namespace:ClientUIMVVMApp2.ViewModels"
        mc:Ignorable="d"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"
        x:Class="ClientUIMVVMApp2.Views.ShowBookInformation" 
        Title="ShowBookInformation Page"
        d:DesignWidth="640" d:DesignHeight="480">

    <Intersoft:UXPage.Resources>
        <ViewModels:BookViewModel x:Key="BookViewModel"></ViewModels:BookViewModel>
    </Intersoft:UXPage.Resources>

    <Grid x:Name="LayoutRoot" Background="Black" >
        <Intersoft:UXItemsControl DataContext="{StaticResource BookViewModel}" Height="110" Width="250" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" CornerRadius="8" Padding="0,0,0,10">
            <Intersoft:StylishLabel Content="Book Details" CornerRadius="8,8,0,0" Margin="0,0,0,10"/>
            <Intersoft:FieldLabel Header="Title:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
                <Intersoft:UXTextBox HorizontalAlignment="Center" Width="132" Text="{Binding Book.Title, Mode=TwoWay, ValidatesOnDataErrors=True}" Intersoft:DataBinding.ClearErrorOnTextInput="True"/>
            </Intersoft:FieldLabel>
            <Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
                <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60" Text="{Binding Book.Price, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:c\}}" Intersoft:DataBinding.ClearErrorOnTextInput="True"/>
            </Intersoft:FieldLabel>
        </Intersoft:UXItemsControl>
    </Grid>
</Intersoft:UXPage>

ValidationViewModel.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;

namespace ClientUIMVVMApp2.ViewModels
{
    public class ValidationViewModelBase : ViewModelBase, IDataErrorInfo
    {
        #region Properties

        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        public virtual bool HasErrors
        {
            get
            {
                return _errors.Count > 0;
            }
        }

        #endregion

        #region Public

        public void SetError(string propertyName, string errorMessage)
        {
            _errors[propertyName] = errorMessage;
            this.OnPropertyChanged(propertyName);
        }

        #endregion

        #region Protected

        protected void ClearError(string propertyName)
        {
            this._errors.Remove(propertyName);
        }

        protected void ClearAllErrors()
        {
            List<string> properties = new List<string>();

            foreach (KeyValuePair<string, string> error in this._errors)
                properties.Add(error.Key);

            this._errors.Clear();

            foreach (string property in properties)
                this.OnPropertyChanged(property);
        }

        #endregion

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                if (this.HasErrors)
                    return this._errors.First().Value;

                return null;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (this._errors.ContainsKey(columnName))
                {
                    return this._errors[columnName];
                }
                return string.Empty;
            }
        }

        #endregion
    }
}

BookViewModel.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ClientUIMVVMApp2.Models;
using System.Windows.Resources;
using System.Xml.Linq;
using System.Linq;
using System.Collections.ObjectModel;

namespace ClientUIMVVMApp2.ViewModels
{
    public class BookViewModel : ValidationViewModelBase
    {
        // Fields
        private Book _book;

        // Constructor
        public BookViewModel()
        {
            this.Book = new Book { Title = "Excel 2007 For Dummies", Price = 15.83 };
            this.Book.EnableValidation = true;
        }

        // Views
        public Book Book
        {
            get { return this._book; }
            set
            {
                if (this._book != value)
                {
                    this._book = value;
                    OnPropertyChanged("Book");
                }
            }
        }

        public string Title
        {
            get { return this.Book.Title; }
        }

        public string ShortTitle
        {
            get
            {
                if (this.Book.Title.Length < 80)
                    return this.Title;
                else
                    return this.Book.Title.Substring(0, 80) + "...";
            }
        }
    }
}
See Also

Concepts

Other Resources