Wednesday, January 19, 2011

Silverlight, PRISM, MVVM, MEF – Part 4

In my previous post, I explained how to add validation metadata to entities and perform data validation on views in the prism application. The standard validation attributes that ship in the System.ComponentModel.DataAnnotations assembly can cover many common validation scenarios. But if you want to do perform custom validations on the business logic, you need to use the CustomValidationAttribute to implement the validation logic. Like the standard validation attributes, it also allows you to specify an ErrorMessage and the properties that failed the validation. 
Custom validations can be implemented in a separate class which has static methods that perform the validation. For e.g
public partial class Customer
    [CustomValidation(typeof(CustomerRules), "ValidateCustomer")]
    internal sealed class CustomerMetadata
        private CustomerMetadata()

        [CustomValidation(typeof(CustomerRules), "IsValidJoiningDate")]
        public DateTime? DateOfJoining { get; set; }

The above sample code has custom validations implemented on entity and property level. The validation rules are implemented in the CustomerRules class which is shared between the server and the client.
public class CustomerRules
    public static ValidationResult ValidateCustomer(Customer customer, ValidationContext context)
        if (string.Compare(customer.FirstName, customer.LastName, StringComparison.OrdinalIgnoreCase) == 0)
            return new ValidationResult("First name and last name cannot be same", new string[] { "FirstName", "LastName" });
        return ValidationResult.Success;

    public static ValidationResult IsValidJoiningDate(DateTime? joiningDate, ValidationContext context)
        if (joiningDate.HasValue)
            if(joiningDate.Value.Year < 1990 || joiningDate.Value.Year > 2011)
                return new ValidationResult("Joining date should be between 01-01-1990 && 31-12-2011", new string[] { "DateOfJoining"});
        return ValidationResult.Success;
In the client code XAML, you just need to set the NotifyOnValidationError property to True to notify the user on validation errors
<TextBox Text="{Binding CurrentCustomer.FirstName, Mode=TwoWay, NotifyOnValidationError=True}" Grid.Column="1" Grid.Row="2" Width="250" Height="25" HorizontalAlignment="Left" />
<TextBox Text="{Binding CurrentCustomer.LastName, Mode=TwoWay, NotifyOnValidationError=True}" Grid.Column="3" Width="250" Height="25" HorizontalAlignment="Left" Grid.Row="3" />
<Button Grid.Row="4" Content="Add" prism:Click.Command="{Binding AddCustomerCommand}" Width="120" HorizontalAlignment="Right" />
<telerik:RadGridView HorizontalAlignment="Left" Grid.ColumnSpan="2" Name="radGridView1" VerticalAlignment="Top" ItemsSource="{Binding Customers}" SelectedItem="{Binding CurrentCustomer, Mode=TwoWay}" AutoGenerateColumns="False">
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Id, NotifyOnValidationError=True, Mode=TwoWay}" IsReadOnly="True" Header="Customer ID" Width="100" />
        <telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName, NotifyOnValidationError=True, Mode=TwoWay}" Header="First Name" Width="200" />
        <telerik:GridViewDataColumn DataMemberBinding="{Binding LastName, NotifyOnValidationError=True, Mode=TwoWay}" Header="Last Name" Width="200" />
        <telerik:GridViewDataColumn DataMemberBinding="{Binding DateOfJoining, NotifyOnValidationError=True, Mode=TwoWay}" Header="Joined On" Width="200" />



Jijo V.G said...

Did not got time to read this yet. Thanks for sharing..Was really helpful..

Riri said...

Hi there
This is a very good topic and i was looking for the best solution to achieve custom validation in prism/mef. Any chance you can upload the sln ?