Windows 8.1 and Prism – Simplest Validation with MVVM

In this article, I will demonstrate handling validations when developing Windows 8 store apps using Prism and MVVM in simplest manner.

First of all, create Windows 8 Blank App project and name is whatever you want. Then get Prism for Windows 8 store apps, you can do it via Manage NuGet packages from Visual Studio and search for “Prism store apps” or run following command from package manager console:

PM> Install-package Prism.StoreApps

Now we will quickly setup simple screen following MVVM. For that, just add class named Person with following set of properties as shown in Listing 1.0.

    public class Person : ValidatableBindableBase
    {
         private string firstName;
        [Required(ErrorMessage = "First name is required.")]
        public string FirstName
        {
            get { return firstName; }
            set
            {
                firstName = value;
                 this.OnPropertyChanged("FirstName");
            }
        }

         private string lastName;
        public string LastName
        {
            get { return lastName; }
            set
            {
                lastName = value;
                 this.OnPropertyChanged("LastName");
            }
        }


         private string email;

        [Required(ErrorMessage = "Email is required.")]
        [RegularExpression(@"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$", ErrorMessage = "Email is invalid.")]
        public string Email
        {
            get { return email; }
            set
            {
                email = value;
                 this.OnPropertyChanged("Email");
            }
        }
    }

Listing 1.0 Person class inheriting ValidatableBindableBase

As per Listing 1.0, in the Person class, we have used DataAnnotations to apply validation for FirstName and Email property and made them required as well Email property to follow proper email format by validating through regex. Other thing to notice is that we have inherited the class from ValidatableBindableBase. This base class has method named ValidateProperties which enables validating all these properties. Apart from that, it has few useful events and properties which helps validating the object as shown in Listing 1.1 below.

     public class ValidatableBindableBase : BindableBase, IValidatableBindableBase, INotifyPropertyChanged
    {
        public ValidatableBindableBase();

         public BindableValidator Errors { get; }
         public bool IsValidationEnabled { get; set; }

         public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public ReadOnlyDictionary<string, ReadOnlyCollection<string>> GetAllErrors();
        public void SetAllErrors(IDictionary<string, ReadOnlyCollection<string>> entityErrors);
        protected override bool SetProperty<T>(ref T storage, T value, string propertyName = null);
        public bool ValidateProperties();
    }

Listing 1.1 ValidatableBindableBase class

Now it’s time to create ViewModel class which simply will have a Person property to bind to the View as well Validate person command to validate all these properties as shown in Listing 1.2 below.

using Microsoft.Practices.Prism.StoreApps;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;

namespace PrismValidation
{
    public class MainViewModel : BindableBase
    {
         public Person Person { get; set; }
        public ICommand ValidatePersonCommand { get; set; }

         private ObservableCollection<string> allErrors;
         public ObservableCollection<string> AllErrors
        {
            get { return allErrors; }
            set
            {
                allErrors = value;
                 this.OnPropertyChanged("AllErrors");
            }
        }

         public MainViewModel()
        {
             this.Person = new Person();
             this.ValidatePersonCommand = new DelegateCommand(this.ExecuteValidatePerson);
        }

        private void ExecuteValidatePerson()
        {
            if (!this.Person.ValidateProperties())
             {
                 this.AllErrors = new ObservableCollection<string>(this.Person.Errors.GetAllErrors().Values.SelectMany(c => c).ToList());
             }
             else
            {
                 this.AllErrors = new ObservableCollection<string> { "Person is valid." };
            }
        }
    }
}

Listing 1.2 MainViewModel class

Listing 1.2 shows that MainViewModel class has one Person property to bind to the view as well ValidatePersonCommand which we will bind to Button control in the view to enable validation. The AllErrors collection will display all the errors on the UI. Let’s complete remaining View part of this example to see it in action.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" >
            <StackPanel.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="FontSize" Value="22"/>
                    <Setter Property="Margin" Value="10"/>
                    <Setter Property="FontSize" Value="22"/>
                </Style>
                <Style TargetType="TextBox">
                    <Setter Property="FontSize" Value="22"/>
                    <Setter Property="Margin" Value="10"/>
                    <Setter Property="FontSize" Value="22"/>
                    <Setter Property="Width" Value="500"/>
                    <Setter Property="HorizontalAlignment" Value="Left"/>
                 </Style>
             </StackPanel.Resources>
             <TextBlock>First Name</TextBlock>
            <TextBox Text="{Binding Person.FirstName, Mode=TwoWay}"/>
            <TextBlock>Last Name</TextBlock>
            <TextBox Text="{Binding Person.LastName, Mode=TwoWay}"/>
            <TextBlock>Email</TextBlock>
            <TextBox Text="{Binding Person.Email, Mode=TwoWay}"/>
            <Button Command="{Binding ValidatePersonCommand}" Margin="10" FontSize="28">Validate</Button>
            <ItemsControl ItemsSource="{Binding AllErrors}" Margin="10" FontSize="22" Foreground="Yellow"/>
        </StackPanel>
    </Grid>

Listing 1.3 MainPage.xaml markup

The markup is self-explanatory as it binds controls to the Person property of the MainViewModel as well ValidatePersonCommand along with AllErrors collection to show errors in the view. Now last remaining thing is to set DataContext of the MainPage to the instance of MainViewModel as following in MainPage’s constructor.

public MainPage()
        {
             this.InitializeComponent();
             this.DataContext = new MainViewModel();
        }

Listing 1.4 Setting DataContext for MainPage

We are good to press F5 and see it in action.
• Just Press Validate button and you will see it reports two errors.
• Enter some invalid format for Email and hit validate to see error being report.

You can grab the source here.




By jay nanavati   Popularity  (3516 Views)