WPF Validations using DataAnnotation and INotifyDataErrorInfo

DataAnnotations and INotifyDataErrorInfo provides an easy and cleaner way to implement validations in WPF ViewModels. Unlike IDataErrorInfo, INotifyDataErrorInfo allows you to raise multiple errors (there are many more features which makes it more interesting than IDataErrorInfo including making it possible to use asynchronous validations).

This being a hands-on demonstration, we will keep the theoritical part to the minimum and hit the code at the earliest. We will begin by writing our little Model class, which would be used for demonstration.

public class Model
{
    [Required(ErrorMessage = "Name cannot be empty")]
    [StringLength(9, MinimumLength = 3, ErrorMessage = "Name should have min 3 characters and max 9")]
    public string Name { get; set; }
    [Required]
    [Range(0,100,ErrorMessage = "Age should be between 1 and 100")]
    public int Age { get; set; }
}


Not too much to explain there. We have used the DataAnnotationAttribute to specify requirements of each property. We will now define a View to display this model. We will get to the ViewModel last, because thats where the trick lies.

<Grid>
    <StackPanel>
        <Grid Margin="10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*"/>
                <ColumnDefinition Width="7*"/>
            </Grid.ColumnDefinitions>

            <Label Content="Name"/>
            <TextBox Grid.Column="1" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" >
                <Validation.ErrorTemplate>
                    <ControlTemplate>
                        <StackPanel>
                            <AdornedElementPlaceholder x:Name="textBox"/>
                            <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                        </StackPanel>
                    </ControlTemplate>
                </Validation.ErrorTemplate>
            </TextBox>
        </Grid>

        <Grid Margin="10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*"/>
                <ColumnDefinition Width="7*"/>
            </Grid.ColumnDefinitions>

The most significant part here is of course the property ValidatesOnNotifyDataErrors being set to true. Additionally I have also used ErrorTemplate to display the error but that is more of an implementation detail for this particular demo, you could opt for the default template or choose another that suits your needs.

The next task obiovusly would be to implement the INotifyDataErrorInfo property in your ViewModel. The INotifyDataErrorInfo is defined as following.

 public interface INotifyDataErrorInfo
 {
       bool HasErrors { get; }
       event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
       IEnumerable GetErrors(string? propertyName);
 }


As noticed, the interface comprises mainly of a property,method and event.

  • HasErrors : Indicates a value whether the current entity has Validation errors. This is a read-only property.
  • GetErrors : A Method which retrieves all the validation errors for the given Property. The property name is passed via parameter.
  • ErrorsChanged : This event would be raised each time the Validation errors has changed for a particular property or for the Entity as a whole.

Let us go ahead and implement our view model. We will use a dictionary to store the errors.

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

The next step is to create our Properties.

private Model _model = new ();

public string Title => "Data Annotation and INotifyDataErrorInfo";
public string Name
{
    get => _model.Name;
    set
    {
        if (Equals(_model.Name, value)) return;

        _model.Name = value;
        NotifyOfPropertyChange();
        Validate(value);
    }
}


public int Age
{
    get => _model.Age;
    set
    {
        if (_model.Age == value) return;

        _model.Age = value;
        NotifyOfPropertyChange();
        Validate(value);
    }
}

Notice a method Validate is being invoked each time a property changes. This method is responsible for validating the property and maintaining the dictionary of errors.

The implementation of Validate looks like following.

private void Validate(object val, [CallerMemberName] string propertyName = null)
{
    if (_errors.ContainsKey(propertyName)) _errors.Remove(propertyName);

    ValidationContext context = new ValidationContext(_model) { MemberName = propertyName };
    List<ValidationResult> results = new();

    if (!Validator.TryValidateProperty(val, context, results))
    {
        _errors[propertyName] = results.Select(x => x.ErrorMessage).ToList();
    }

    ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}

What remains now is to impement our interface, which is pretty straightforward.

public bool HasErrors => _errors.Any();

public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

public IEnumerable GetErrors(string propertyName)
{
    return _errors.ContainsKey(propertyName) ? _errors[propertyName] : null;
}

The complete ViewModel looks like following.

public class DataAnnotionViewModel : ViewModelBase, INotifyDataErrorInfo
{
    private IDictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();
    private Model _model = new ();

    public string Title => "Data Annotation and INotifyDataErrorInfo";
    public string Name
    {
        get => _model.Name;
        set
        {
            if (Equals(_model.Name, value)) return;

            _model.Name = value;
            NotifyOfPropertyChange();
            Validate(value);
        }
    }


    public int Age
    {
        get => _model.Age;
        set
        {
            if (_model.Age == value) return;

            _model.Age = value;
            NotifyOfPropertyChange();
            Validate(value);
        }
    }

    private void Validate(object val, [CallerMemberName] string propertyName = null)
    {
        if (_errors.ContainsKey(propertyName)) _errors.Remove(propertyName);

        ValidationContext context = new ValidationContext(_model) { MemberName = propertyName };
        List<ValidationResult> results = new();

        if (!Validator.TryValidateProperty(val, context, results))
        {
            _errors[propertyName] = results.Select(x => x.ErrorMessage).ToList();
        }

        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }

    public bool HasErrors => _errors.Any();

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public IEnumerable GetErrors(string propertyName)
    {
        return _errors.ContainsKey(propertyName) ? _errors[propertyName] : null;
    }
}

That’s all you need for Validating your ViewModels using DataAnnotationAttribute and INotifyDataErrorInfo. The complete code sample is available in my Github here.

Why Initialize Collection Size

In possibly every code base you might have seen, usage of Collections would have been a common sight. The introduction of Generic Collections in early stages of evolutin of language has made is all the more favourite of developers comparing to the non-generic cousins that existed before. One of the most common patterns seen in any code base is as follows.

var persons = GetPersonList();
var studentList = new List<Student>();
foreach(var person in persons)
{
    studentList.Add(new Student
    {
        FirstName = person.FirstName,
        LastName = person.LastName
    });
}

At the first glance, there is nothing wrong with the code. In fact, it works well too. Unlike arrays, one doesn’t need to declare the size of List beforehand, and it sort of magically does the trick to expand itself. However, there is a hidden problem caused due to the optimized way the Collection is implemented to magically expand.

Beneath the List declaration, there is still an array, which is made to resize according to the ever growing requirements of the Collection. This is done in the Add method, which is defined as

public void Add(T item) 
{
    if (_size == _items.Length) EnsureCapacity(_size + 1);
    _items[_size++] = item;
    _version++;
}

private void EnsureCapacity(int min) 
{
    if (_items.Length < min) {
        int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;

        if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
        if (newCapacity < min) newCapacity = min;
        Capacity = newCapacity;
    }
}

The Add() method checks if the array is full, and if so, it calls the EnsureCapacity method to double the Capacity.

The resizing of course happens in the Capacity Property.

public int Capacity 
{
    get {
        Contract.Ensures(Contract.Result<int>() >= 0);
        return _items.Length;
    }
    set {
        if (value < _size) {
            ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
        }
        Contract.EndContractBlock();

        if (value != _items.Length) {
            if (value > 0) {
                T[] newItems = new T[value];
                if (_size > 0) {
                    Array.Copy(_items, 0, newItems, 0, _size);
                }
                _items = newItems;
            }
            else {
                _items = _emptyArray;
            }
        }
    }
}

The key take away from the Add/EnsureCapcity methods is that every time the size of array is breached, the capacity of the array is doubled. This leads to couple of undesired things.

  • Expensive operation to resize the array

As the List grows, there would innumerous expensive resizing operations, which is quite undesired.

  • Possibility that a lot of memory spaces left allocated but unused.

Consider if the number of Person in the personList is 258. Due to the logic shown above, the Capacity of Array would now 512. That is a whole lot of unused allocated memory space when you are working with memory intensive application.

// Default Behavior
Console.WriteLine($"StudentList(Count={studentList.Count},Capacity={studentList.Capacity})");
// Output
StudentList(Count=258,Capacity=512)

The ideal way to counter this would be to use overloaded constructor and initialize the size of array.

var studentList = new List<Student>(persons.Count());

This would reduce the need for resizing of internal array.

// With Collection Size Iniitialized as above
 Console.WriteLine($"StudentList(Count={studentList.Count},Capacity={studentList.Capacity})");
// Output
StudentList(Count=258,Capacity=258)

Of course there could be places where you might not be having the convenience of knowing the collection size beforehand. But still, if you are able to be pick an initial size well, you could eliminate or reduce the need to resize the array.

MahApps HamburgerMenu and Caliburn Micro

MahApps is probably one of the most used UI library among WPF developers, with a galaxy of great controls. Despite that, recently I was surprised to see lack of proper example for Hamburger Menu control, particulary MVVM based. I was also more keen to know how to make best use of capabilities of Caliburn Micro along the way.

Here is how I ended up achieving my objectives.

XAML : Control, Content, ItemTemplate and HeaderTemplate

The first step would be to define the Control in Xaml, along with desired ContendTemplate,ItemTemplate and HeaderTemplate.

<mah:HamburgerMenu x:Name="Menu" DisplayMode="CompactOverlay" SelectedItem="{Binding ActiveItem,Converter={StaticResource SelectedItemConverter}}"
           ItemsSource="{Binding MenuItems,Converter={StaticResource MenuConverter}}"
           cal:Message.Attach="[Event ItemClick]=[Action MenuSelectionChanged($source,$eventArgs)]"
           HamburgerMenuHeaderTemplate="{StaticResource MenuHeaderTemplate}"
           ItemTemplate="{StaticResource MenuItemTemplate}">
    <mah:HamburgerMenu.Content>
       <ContentControl Grid.Column="0" Grid.Row="1" x:Name="ActiveItem" />
    </mah:HamburgerMenu.Content>
</mah:HamburgerMenu>

As you would have noticed couple of converters in here. We will get to that in a moment, but first let us define our MenuItemTemplate and MenuHeaderTemplate.

<!-- Menu Header Template -->
<DataTemplate x:Key="MenuHeaderTemplate">
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"  FontSize="16"  Foreground="White"  Text="Sample App" />
</DataTemplate>

<!-- Menu Item Template -->
<DataTemplate x:Key="MenuItemTemplate">
    <Grid x:Name="RootGrid" Height="48" Background="Transparent">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="48" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Column="0"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Content="{Binding Icon}"
            Focusable="False" />
        <TextBlock Grid.Column="1"
           VerticalAlignment="Center"
           FontSize="16"
           Text="{Binding Label}" />
    </Grid>
</DataTemplate>

At this point, we need to create our ViewModels for each of the menu items. As we notice from the templates above, there are couple of fields which are required for each of Menu Items – a Title, and a Icon (_Icon is not quite mandatory, depending on the type of Menu Item you are creating).

Destination ViewModels

Let us go ahead and define our ViewModels for Menu Items.

public class PageViewModelBase : Screen
{
    public virtual string Title { get; }
    public virtual object Icon { get; }
}
public class HomePageViewModel : PageViewModelBase
{
    public override string Title => "Home";
    public override object Icon => new PackIconMaterial { Kind = PackIconMaterialKind.Home };
}
public class ProfilePageViewModel : PageViewModelBase
{
    public override string Title => "Profile";
    public override object Icon => new PackIconMaterial { Kind = PackIconMaterialKind.AccountStar };
}

In the above example, we are using the MahApps.Metro.IconPack for Icons, but that is only an implementation detail which could can easily vary. For sake of simplicity, I have omitted the Views here, but that could be found in the example solution given in the end of this article.

The Glue : ValueConverters and ActiveItem

We now have different ViewModels defined, and it is time to create the dynamic collection to bind to our HamburgerMenu Control. So, in our ShellViewModel, we will do the following.

public ShellViewModel()
{
    MenuItems = new List<PageViewModelBase>
    {
        new HomePageViewModel(),
        new ProfilePageViewModel()
    };
}

public IEnumerable<PageViewModelBase> MenuItems { get; }

We are almost there, and now as the final step, we need to write our converters. There are two converters involved,

  • PageToMenuItemConverter – Converts from ViewModel Collection to HamburgerMenuIconItem.
  • SelectedItemConverter – Parse the ViewModel from SelectedItem
public class PageToMenuItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is IEnumerable<PageViewModelBase> nmItemCollection)
        {
            return nmItemCollection.Select(item => new HamburgerMenuIconItem
            {
                Tag = item,
                Icon = item.Icon,
                Label = item.Title
            });
        }
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class SelectedItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is HamburgerMenuIconItem menuItem ? menuItem.Tag : value;
    }
}

That’s all we need. Your menu would be up and running now. You can find the example code in my Github here

Bootstrap 4 Theming – Changing Primary Color

Bootstrap allows you to customize the existing definition greatly. With Bootstrap 4, the way we customize the theming has changed a bit, and that’s exactly what I would like to explain here – step by step.

Step 1: Get the Bootstrap source

Of course you need to get the bootstrap source to customize it. You would then recompile it to get the required css.

We could use npm to get the source.

 npm install bootstrap --save

Step 2: Install Sass compiler

We would rely on Sass to customize the variables and maps for creating our custom bootstap. You could head over to the Sass Website to read the installation instruction in detail. But I have tried to highlight the necessary steps.

You would need to install Ruby first and then follow it up with the following command.

npm install -g sass

Step 3: Arrange your folder structure.

The last step before we actually start customizing is to arrange the folder structure as mentioned by the Bootstrap website.

your-project/
├── scss
│   └── custom.scss
└── node_modules/
    └── bootstrap
        ├── js
        └── scss

Step 4: Customize your theme.

You cutomize your theme by modiying the variables and maps in the bootstrap code. Using your custom.css you import the whole bootstrap source (you could alternatively pick and choose if you are sure).

@import "node_modules/bootstrap/scss/bootstrap";

The way team bootstrap has written the code is that it allows you to customize the variable, provided it is defined before the import.

In this example, we will alter the Primary color to a shade of purpose.

$theme-colors: (
  "primary": #4b1076,
);
@import "node_modules/bootstrap/scss/bootstrap";


Step 5: Compile your scss and include in your application

Now all that is left is to compile your custom.scss and create your css which you can then use in your application. To compile the scss, use the following command.

sass custom.scss custom.css

That’s all you need.