Saturday, July 24, 2010

Synching View Model with Data Model

In MVVM, property notification mechanisms allow to notify the view for changes in the property values in the View Model and otherwise. These mechanisms include implementing INotifyPropertyChanged or using Dependency properties. But how to synchronize between View Model and DataModel?

With INotifyPropertyChanged implementation, this can be achieved by assigning the same property values to the DataModel properties as being set for the View Model properties. So we can use the values of all proxy properties in the View model to their corresponding properties in the DataModel. We can also set the values of other properties based on these proxy properties in the same set block of these properties. e.g. we have a property StudentName in the ViewModel. We have a property with same name in dataModel (student). We can copy the values in the ViewModel as follows:
string _StudentName;
public String StudentName
{
get {...}
set
{
_StudentName = value;
student.StudentName = _StudentName;
PropertyChanged("StudentName");
}
}

With Dependency Properties usage, we inherit our view model with DependencyObject. this gives access to the methods like GetValue() and SetValue(). The problem in when these properties are registered with WPF property system. The WPF runtime does not use the set block to set the property value. It directly calls SetValue() on this property if this property is registered with WPF property system. So how should we pass on these values to the Data model if model needs real time updates based on user interaction with the view.

Many a times people use different techniques to resolve this. The easiest is using the DependencyPropertyDescriptor. DependencyPropertyDescriptor allows to provide the description of intended dependency property. One of the description is getting the Value change notification for this property. It enables other objects to be notified when there is a change in the property.

Let's consider an example. We create a window Window1 with a text box Window1.


The above window is defined as follows:
<Window x:Class="DPDescriptor.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DPDescriptor"
DataContext="{DynamicResource ViewModel}"
Title="Window1" Height="302" Width="397">
<Window.Resources>
<local:Student x:Key="ViewModel" x:Name="_vm" />
</Window.Resources>
<Grid>
<Label Height="22" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" Width="43">Name</Label>
<TextBox Height="22" Margin="0,12,12,0" Name="txtName" VerticalAlignment="Top"
HorizontalAlignment="Right" Width="302" >
<TextBox.Text>
<Binding Path="StudentName" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
</Grid>
</Window>

As you can see above, we have added a text box and a label to the window. We have also instantiated Window1ViewModel with ViewModel key. We have specified this as the data context of this window. The text box is data bound with its StudentName property. The UpdateSourceTrigger is set as PropertyChanged. This would cause copying the value to be copied to the DataContext for every change by the user.

The code behind of the this window is as follows:

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}

It is the default code behind. We are not doing anything special here.

Now we provide the definition of the Window1ViewModel as expected by the above Window. In the View Model we are using student object as our data model, instantiated in the constructor. The view model is registering StudentName property with WPF property system.
class Window1ViewModel : DependencyObject
{
Student student;

#region Constructors
public Window1ViewModel()
{
student = new Student();
StudentNameDescriptor.AddValueChanged(this,
(o, e) => student.StudentName = this.StudentName );
}
#endregion

#region StudentName Property
public static DependencyProperty StudentNameProperty =
DependencyProperty.Register("StudentName", typeof(string), typeof(Window1ViewModel));

public string StudentName
{
get { return (string)GetValue(StudentNameProperty); }
set { SetValue(StudentNameProperty, value); }
}

public DependencyPropertyDescriptor StudentNameDescriptor =
DependencyPropertyDescriptor.FromProperty(StudentNameProperty, typeof(Window1ViewModel));
#endregion
}

The most important thing in the above code is StudentNameDescriptor. This descriptor is defining a ValueChange event handler for StudentName property. Whenever the value of StudentName is updated, the below lambda statement is executed (which copies the view model's property to the data model's property):
(o, e) => student.StudentName = this.StudentName

The Student class is defined as follows for the above example:
class Student
{
public string StudentName { get; set;}
}

Using ICollectionView for Sorting and Filtering

WPF allows us to great support for manipulating the display which is data bound to different collections. Most of these collections support ICollectionView functionality. In this discussion, we will discuss how we can use ICollectionView for filtering and sorting our collection. It must be remembered that ICollectionView also supports grouping.

In this example, we want to create a window as follows:


So we have a list box showing the list of names students. We want to provide the functionality to search within the list based on the user input in the Search text box on top left of the window. We also want to provide sorting functionality using the "Toggle Sort" on top right. When the form opens the list should be sorted in ascending order of names of students.

Let's start by creating a Student class. This holds the name of student and his ID.
class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
}

First we create the view for the above in XAML.
<Window x:Class="ICollectionViewExampleCS.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ICollectionViewExampleCS"
Title="Window1" Height="356" Width="616" DataContext="{DynamicResource ViewModel}">
<Window.Resources>
<local:Window1ViewModel x:Key="ViewModel" x:Name="_vm" />
</Window.Resources>
<Grid>
<ListBox Margin="12,41,7,7" Name="listBox1" ItemsSource="{Binding StudentList}" DisplayMemberPath="StudentName" />
<TextBox Height="23" x:Name="txtSearchPattern" Text="{Binding Path = SearchPattern, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="118" />
<Button Height="23" HorizontalAlignment="Right" Margin="0,12,7,0" Name="button1" VerticalAlignment="Top" Width="74" Click="button1_Click">Toggle Sort</Button>
</Grid>
</Window>

As you can see, we are using ViewModel as the DataContext of the window (Window tag) using dynamic resource extension. The definition of ViewModel is provided in Window.Resources section as an instance of Window1ViewModel class. We are binding the Search textbox with SearchPattern property from the DataContext. The UpdateSourceTrigger for this binding is set as PropertyChanged. So as the user would be typing and deleting the text, it would automatically update itself in the datacontext. The Click event of ToggleSort button has been provided with a button1_Click handler. This handler should use the sort functionality from the DataContext. The list box is bound with StudentList property from the datacontext. This should be a collection. We are displaying StudentName from the individual item of this list.

The code behind of this window is as follows:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}

private void button1_Click(object sender, RoutedEventArgs e)
{
((Window1ViewModel)this.Resources["ViewModel"]).sortStudents();
}
}

Here we have provided the definition of button1_Click handler. It is calling sortStudents method from the DataContext. Being a big fan of MVVM, I don't recommend calling the DataContext events like this but in order to keep the example simple I am making this call.

Now we have the idea of everything we would be requiring from Window1ViewModel. It should be providing two properties StudentList and SearchPattern. The StudentList should be a collection of students. It must have a StudentName field. Additionally SearchPattern should filter StudentList based on updates in its value.
internal class Window1ViewModel : DependencyObject
{
public ObservableCollection StudentList { get; private set; }

public Window1ViewModel()
{
StudentList = new ObservableCollection();
addStudents();
sortStudents();
SearchPatternDescriptor.AddValueChanged(this, (o, e) => filterStudents());
}

private void addStudents()
{
StudentList.Add(new Student() { StudentID = 1, StudentName = "Muhammad" });
StudentList.Add(new Student() { StudentID = 2, StudentName = "Michael" });
StudentList.Add(new Student() { StudentID = 3, StudentName = "Shoaib" });
StudentList.Add(new Student() { StudentID = 4, StudentName = "Shahbaz" });
StudentList.Add(new Student() { StudentID = 5, StudentName = "Maria" });
StudentList.Add(new Student() { StudentID = 6, StudentName = "Mehreen" });
StudentList.Add(new Student() { StudentID = 7, StudentName = "Imran" });
StudentList.Add(new Student() { StudentID = 8, StudentName = "Naveed" });
StudentList.Add(new Student() { StudentID = 9, StudentName = "Muhammad" });
StudentList.Add(new Student() { StudentID = 10, StudentName = "Mustafa" });
StudentList.Add(new Student() { StudentID = 11, StudentName = "Asad" });
}

public static DependencyProperty SearchPatternProperty =
DependencyProperty.Register("SearchPattern", typeof(string), typeof(Window1ViewModel));
public string SearchPattern
{
get
{
return (string)GetValue(SearchPatternProperty);
}
set
{
SetValue(SearchPatternProperty, value);
}
}
DependencyPropertyDescriptor SearchPatternDescriptor =
DependencyPropertyDescriptor.FromProperty(SearchPatternProperty, typeof(Window1ViewModel));

public void filterStudents()
{
ICollectionView view = CollectionViewSource.GetDefaultView(this.StudentList);
if (string.IsNullOrEmpty(SearchPattern))
view.Filter = null;
else
view.Filter = new Predicate<object>((o) => ((Student)o).StudentName.StartsWith(SearchPattern));
}

public void sortStudents()
{
ICollectionView view = CollectionViewSource.GetDefaultView(this.StudentList);

if (view.SortDescriptions.Count > 0)
{
ListSortDirection direction = view.SortDescriptions[0].Direction ==
ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
view.SortDescriptions.Clear();
view.SortDescriptions.Add(new SortDescription("StudentName", direction));
}
else
view.SortDescriptions.Add(new SortDescription("StudentName", ListSortDirection.Ascending));
}

}

For keeping a track of updates in SearchPattern property, we needed to define a DependencyPropertyDescriptor. We named it as SearchPatternDescriptor. We have provided a lambda expression for its delegate which is just calling filterStudents method.

In the filterStudents() method, we are using ICollectionView to filter the StudentList. ICollectionView supports filtering using its Filter property. We can specify a predicate for this property. The collection is filtered by this predicate then. If SearchPattern is empty, then we are removing all the Filter, otherwise, we are updating the filter with the new Predicate.

For sorting, as expected by the view, we have provided the definition of sortStudents() method. This also uses ICollectionView for sorting. ICollectionView supports sorting by adding SortDescription to its SortDescriptions collection. Each SortDescription can have ascending or descending order. In our example, we are checking for sort direction. We are clearing all sort descriptions and providing new SorDescription with the opposite direction.

Sunday, July 18, 2010

WPF Validation - Using Validation Application Block

As most of us like to take advantage of Enterprise library for many of required cross cutting concerns, we wish to use them with every technology we use to develop our softwares. One of the most used application block in Enterprise library is Validation Application Block. The great feature of this application block is that we can specify validation logic in different places including code, attributes and configuration files. We love it!!!

The issue was that this application block was not providing any built-in support for Windows Presentation Foundation. As we know for validating data in a WPF form, we generally use one of the specializations of ValidationRule class. We needed support for hooking up the validation logic specified in Validation Application Block with these Validation rules. It might be a news for you that the updated Validation Block released with Enterprise library 5.0 supports this. Zindabad!!!

Enterprise library 5.0 can be downloaded from this location:
http://www.microsoft.com/downloads/details.aspx?FamilyId=bcb166f7-dd16-448b-a152-9845760d9b4c&displaylang=en


After downloading install it. You will have to reference the assemblies as specified below:



In this post, we will specify our validation logic in the following places individually and combinations of them and see how we can use them in our WPF XAML.
  1. Attributes
  2. Configuration
  3. Code

Validation specification in Attributes
Let us create our View Model. We name it as StudentViewModel. Please notice that we have included two namespaces System.Windows (for DependencyProperty) and Microsoft.Practices.EnterpriseLibrary.Validation.Validators (for Validation attributes).

namespace ValidationBlockExampleWPF
{
using System.Windows;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

class StudentViewModel : DependencyObject
{
[StringLengthValidator(5, RangeBoundaryType.Inclusive, 20, RangeBoundaryType.Inclusive,
MessageTemplate = "[{0}]Name must be between {3} and {5} characters.")]
public string StudentName
{
get { return (string) GetValue(StudentNameProperty); }
set { SetValue(StudentNameProperty, value); }
}

public static DependencyProperty StudentNameProperty =
DependencyProperty.Register("StudentName", typeof(string), typeof(StudentViewModel));
}
}


In this simple View model, we have created a property StudentName. We have registered it with WPF property system. We have specified validation for this property. These only validation is about limitations for width (5 to 20 characters). Here Inclusive means that boundary values (5 and 20) are included in Valid limits for length. In the case that this property exceeds this limit, error message can be obtained as provided in the MessageTemplate in validation attribute.

Now let us create a simple WPF window using this View model as its data context.

<Window x:Class="ValidationBlockExampleaWPF.StudentWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ValidationBlockExampleaWPF"
xmlns:vab="clr-namespace:Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WPF;assembly=Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WPF"
Title="StudentWindow" Height="300" Width="540"
DataContext="{DynamicResource ViewModel}" >
<Window.Resources>
<local:StudentViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid>
<Label HorizontalAlignment="Left" Margin="12,20,0,0" Name="label1"
Width="94" Height="21" VerticalAlignment="Top">Student Name</Label>
<TextBox Height="24" Margin="112,20,12,0" Name="textBox1" VerticalAlignment="Top" >
<TextBox.Text>
<Binding Path="StudentName" UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<vab:ValidatorRule SourceType="{x:Type local:StudentViewModel}" SourcePropertyName="StudentName" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</Grid>
</Window>

Here we have added two namespaces local (for the current project) and vab (for using WPF integration features of Validation Application Block). We have bound the only text box in the window with StudentName property of the data context. The most important thing in the above code is following:
<vab:ValidatorRule SourceType="{x:Type local:StudentViewModel}" SourcePropertyName="StudentName" />

It is asking to use the validation logic as specified in the attributes of StudentName property of StudentViewModel class. Now this is to support the cases when we are binding with the view model but want to use validation as specified in any property of any other class (including model classes). In our case, since we have directly specified the validation in view model, we can update the text box definition as follows:
<TextBox Height="24" Margin="112,20,12,0" Name="textBox1" VerticalAlignment="Top" 
vab:Validate.BindingForProperty="Text">
<TextBox.Text>
<Binding Path="StudentName" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>

Here it is asking the runtime to use the validation logic from the property in the data context bound with Text property of the control. Basically, WPF integration in validation block, adds a validation rule whenever it sees this.

We are trying to adhere to MVVM to the best. The code behind of the above window is as follows:

namespace ValidationBlockExampleaWPF
{
///
/// Interaction logic for StudentWindow.xaml
///

public partial class StudentWindow : Window
{
public StudentWindow()
{
InitializeComponent();
}
}
}

Now we run the project. As we start typing the name, we can see the validation being done.



But as the number of characters reach the valid limit, the error adorner is no more displayed with the text box.



Validation specification in Configuration:
As we discussed above, we can also specify validation details in configuration file. Let us define configuration for our view model validation. We can define validation configuration in Enterprise library configuration utility. When you install Enterprise library it is available in start menu:



It must be remembered that in order to define validation configuration in the configuration utility, the type must be public. Let us make our StudentViewModel public and build the project. If we don't want to keep it public, we can later update it. Now it should be available as follows:



Now we add a regular expression validator for our StudentName property. Here we are specifying that StudentName can not start with any digit between 0 and 9. We have defined this validation in BasicInfoRuleSet rule set.



Now save the configuration as App.config. The configuration file is created in xml. If you open the configuration file, you can find that the configuration is defined as follows:
<configuration>
<configSections>
<section name="validation" type="Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.ValidationSettings, Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<validation>
<type name="ValidationBlockExampleaWPF.StudentViewModel" assemblyName="ValidationBlockExampleaWPF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<ruleset name="BasicInfoRuleSet">
<properties>
<property name="StudentName">
<validator type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.RegexValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
pattern="^[^0-9]" name="Regular Expression Validator" />
</property>
</properties>
</ruleset>
</type>
</validation>
</configuration>

We update the StudentName property in StudentViewModel and specify the previously defined validation (length between 5 and 20) as follows:

[StringLengthValidator(5, RangeBoundaryType.Inclusive, 20, RangeBoundaryType.Inclusive,
MessageTemplate = "[{0}]Name must be between {3} and {5} characters.", Ruleset = "BasicInfoRuleSet")]
public string StudentName
{
get { return (string) GetValue(StudentNameProperty); }
set { SetValue(StudentNameProperty, value); }
}

If you have not noticed then let me explain. Some amazing thing has just happened. If you remember from above, we defined our regular expression validator to be part of BasicInfoRuleSet. Now we have added one more validation in the same rule set but now it is in the attributes in code. So the same ruleset can span in multiple places. It is the responsibility of Validation application block to get all the validations defined for the property and decide if the value is valid. Amazing!!!

In order to use the validations from all these different sources, we have to update the text box in StudentWindow as follows:

<TextBox Height="24" Margin="112,20,12,0" Name="textBox1" VerticalAlignment="Top"
vab:Validate.UsingRulesetName="BasicInfoRuleSet" vab:Validate.BindingForProperty="Text" vab:Validate.UsingSource="All">
<TextBox.Text>
<Binding Path="StudentName" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>

Here we have specified that the validation for data entered should be using BasicInfoRuleSet. It should be using the validation defined in all sources possible.

Note:
It must be remembered that in the whole discussion above, the validation would be executed for the converted value and the value would be committed to the bounded property. We can control which value to use (converted / committed etc) using ValidationStep attribute in ValidationRule. So if you want to control which value to use then use ValidationRule tag instead of defining validation in the TextBox itself.



Note:
We can not use Self Validation feature of Validation Application Block with ValidationRule in XAML.

WPF Validation - Using Validation Rules in BindingGroup

This post is part of series of discussions about different validation techniques in WPF. In this post we will be discussing about using Validation rules with Binding Groups. WPF allows us to group bindings in the form of a Binding Group. It allows to associate Validation rules with these binding groups. After validation is done, it provides us notification in the form of an event which can be used for notifying the user about failed validation. We can mark the controls with invalid values or notify the user in the form of a message box or whatever we want to do as a result of passed / failed validation. This event is fired as a result of both new validation error or old validation errors which are now passed because the user has entered new valid values.

Simple Example:
Let's create a window with three text boxes and a button. These three text boxes are used for entering Name, Age and City by the user. Our validation rule suggest that for certain cities, providing Age information is mandatory. The validation logic should be executed when the user clicks the Validate button.
<Window x:Class="wpf_validation.Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:wpf_validation"
Title="Window4" Height="300" Width="641" Validation.Error="Window_Error">
<Window.BindingGroup>
<BindingGroup NotifyOnValidationError="True">
<BindingGroup.ValidationRules>
<local:MyValidationRule ValidationStep="ConvertedProposedValue" />
</BindingGroup.ValidationRules>
</BindingGroup>
</Window.BindingGroup>
<Grid>
<TextBox Height="22" Margin="97,27,97,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding Name}" />
<Label Height="28" HorizontalAlignment="Left" Margin="21,25,0,0" VerticalAlignment="Top" Width="70">Name</Label>
<TextBox Height="22" Margin="97,55,97,0" Name="textBox2" VerticalAlignment="Top" Text="{Binding Age}" />
<Label Height="28" HorizontalAlignment="Left" Margin="21,53,0,0" VerticalAlignment="Top" Width="70">Age</Label>
<TextBox Height="22" Margin="97,83,97,0" Name="textBox3" VerticalAlignment="Top" Text="{Binding City}"/>
<Label Height="28" HorizontalAlignment="Left" Margin="21,81,0,0" VerticalAlignment="Top" Width="70">City</Label>
<Button HorizontalAlignment="Left" Margin="97,111,0,126" Name="button1" Width="118" Click="button1_Click">Validate</Button>
</Grid>
</Window>

WPF allows us to define various binding group within the same control / window. In the case of different binding groups within the same control, we need to specify the binding group name with each binding which we want to be validated with that group. Since ours is a simple example, we have just created one Binding group for the whole window. Setting NotifyOnValidationError as true allows WPF runtime to fire Validation.Error event specified. Let's have a look at the code behind of our window. Here we have specified Window4ViewModel as datacontext of the window. We also have specified click event of Validate button where we have checked for validation result by calling CommitEdit() method on binding group. This returns true for passed validation and false otherwise. For passed validation we are again setting the binding group as being edited. We have also provided the definition of Window_Error event as specified in the XAML above.

We have specified business rule, MyValidationRule, for this Biding group. With the validation rules, we can also specify when we want these validation rules to be executed. This is specified using ValidationStep property of Validation rule. Setting it as ConvertedProposedValue would be evaluating this rule after the entered value is converted. The other options are RawProposedValue, UpdatedValue and CommittedValue.
public partial class Window4 : Window
{
Window4ViewModel _vm;
public Window4()
{
InitializeComponent();
_vm = new Window4ViewModel();
this.DataContext = _vm;
this.BindingGroup.BeginEdit();
}

private void button1_Click(object sender, RoutedEventArgs e)
{
if (this.BindingGroup.CommitEdit())
{
this.BindingGroup.BeginEdit();
}
}

private void Window_Error(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added)
{
if (e.Error.RuleInError.GetType() == typeof(MyValidationRule))
{
BindingGroup bg = (BindingGroup)e.Error.BindingInError;
BindingExpression BindingExprssionAge = (BindingExpression)bg.BindingExpressions[1];
BindingExpression BindingExprssionCity = (BindingExpression)bg.BindingExpressions[2];
ExceptionValidationRule dummyRule = new ExceptionValidationRule();
Validation.MarkInvalid(BindingExprssionAge, new ValidationError(dummyRule, "Age is Invalid!"));
Validation.MarkInvalid(BindingExprssionCity, new ValidationError(dummyRule, "City is invalid!"));
//MessageBox.Show(e.Error.ErrorContent.ToString());

}
}
else if (e.Action == ValidationErrorEventAction.Removed)
{
if (e.Error.RuleInError.GetType() == typeof(MyValidationRule))
{
BindingGroup bg = (BindingGroup)e.Error.BindingInError;
BindingExpression BindingExprssionAge = (BindingExpression)bg.BindingExpressions[1];
BindingExpression BindingExprssionCity = (BindingExpression)bg.BindingExpressions[2];
Validation.ClearInvalid(BindingExprssionAge);
Validation.ClearInvalid(BindingExprssionCity);
}
}
}
}

The Window_Error is fired when a validation results in an error or validation is passed after failing it last time. If the validation has not resulted in failure when last time this validation was executed then WPF runtime does not fire this event. Firing it once when a validation error is removed allows the clean up activities to be executed like clearing the invalid messages. This also provides the error message as specified when ValidationRule is executed resulting in a failed validation. We can get this value with e.Error.ErrorContent.

Below we have provided the definition of Window4ViewModel which was specified as the data context of the window. We have specified three dependency properties Name, Age and City.
class Window4ViewModel : System.Windows.DependencyObject
{
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Window4ViewModel));

public int? Age
{
get { return (int?)GetValue(AgeProperty); }
set { SetValue(AgeProperty, value); }
}
public static DependencyProperty AgeProperty = DependencyProperty.Register("Age", typeof(int?), typeof(Window4ViewModel));

public string City
{
get { return (string)GetValue(CityProperty); }
set { SetValue(CityProperty, value); }
}
public static DependencyProperty CityProperty = DependencyProperty.Register("City", typeof(string), typeof(Window4ViewModel));

}

Finally we need to provide the definition of the business rule, MyValidationRule. The ValidationRule is evaluated by its Validate method. For passed validation, this should return ValidationResult with isValid as true. For failed validation, this should result in a ValidationResult with isValid set as false. Additionally, it can also provide the error message.

The data context is provided as the first item of the parameter value. After getting values from data context, we can run our validation logic and return the appropriate validation result.
public class MyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
ValidationResult validationResult = new ValidationResult(true, null);

BindingGroup bg = value as BindingGroup;
Window4ViewModel vm = bg.Items[0] as Window4ViewModel;

object objAge;
object objCity;

bg.TryGetValue(vm, "Age", out objAge);
bg.TryGetValue(vm, "City", out objCity);

int? Age = (int?)(objAge == DependencyProperty.UnsetValue? null : objAge);
string City = (string)objCity;

if (new string[] { "Karachi", "Shanghai", "New York" }.Contains(City))
{
if (!Age.HasValue)
validationResult = new ValidationResult(false, "For this city, specification of age is mandatory");
}
return validationResult;
}
}

Note:
Validation rules allow to execute the validation logic at different steps controlled through ValidationStep. It can be executed before even the value is converted by the converter, after it is converted and before it is committed to the source or after it is copied to the source. This provides the developer great control over the flow of the application.

Saturday, July 17, 2010

WPF Validation - IDataErrorInfo

This is the third post in the series of discussion about WPF validation. In these posts, we have been discussing the various validation techniques available in Windows Presentation Foundation.

In this post, we will be discussing about IDataErrorInfo.

What is IDataErrorInfo?
IDataErrorInfo is an interface defined in System.ComponentModel namespace. The contract required implementing indexer and a string property named Error.

Let's see IDataErrorInfo in Practice!
We create a window, named Window3. To keep the example simple, we just have a text box in this window, textBox1. The important thing is the binding of this text box. While setting the binding to Name property of the data context, we have also set ValidateOnDataErrors as true. This would use IDataErrorInfo members from the data context for validation of its properties.

<Window x:Class="wpf_validation.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="557">
<Grid>
<TextBox Height="23" Margin="123,32,107,0" Name="textBox1" VerticalAlignment="Top" >
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" />
</TextBox.Text>
</TextBox>
</Grid>
</Window>

Now let's have a look at the code behind of Window3.
public partial class Window3 : Window
{
Window3ViewModel _vm;

public Window3()
{
InitializeComponent();
_vm = new Window3ViewModel();
this.DataContext = _vm;
}
}

As you can see above, we have created an object of Window3ViewModel and assigned it as the data context of the window. Below you can see the definition of Window3ViewModel. As discussed above, since we are using ValidatesOnDataErrors, we need to implement our data context with IDataErrorInfo interface. Additionally, our view is expecting Name property from our data context. Since we will be defining it as dependency property, we need to inherit from DependencyObject which provides GetValue and SetValue method used in the dependency property.
class Window3ViewModel : DependencyObject, IDataErrorInfo
{
public string Name
{
get
{
return (string)GetValue(NameProperty);
}
set
{
SetValue(NameProperty, value);
}
}
public static DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Window3ViewModel));

#region IDataErrorInfo Members

string IDataErrorInfo.Error
{
get
{
return null;
}
}

string IDataErrorInfo.this[string columnName]
{
get
{
string result = null;
switch (columnName)
{
case "Name":
if (!string.IsNullOrEmpty(Name) && System.Text.RegularExpressions.Regex.IsMatch(Name, "[/!@#?/}[}{]"))
{
result = "Invalid Characters in name!";
}

break;
default:
break;
}
return result;
}
}

#endregion
}

In the above code, to implement IDataErrorInfo, we have provided definition of the indexer. This would be called for each binding for which we have set ValidatesOnDataErrors as true. This would be called with name of property as the argument. In this example, it is columnName. This helps us in finding out which property is being set. Then we can provide the validation logic for the particular property. The interesting thing is that we don't have anything like value which gives us some idea about the property being set. As a matter of fact we can directly use property (in our case Name) to get the value being set. This is because this member gets called after property being set with value. So, even if, the validation results in error, we still have the property with invalid value. We might need to check it again before submission of the form if we don't want incorrect values to be submitted.

What is IDataErrorInfo.Error used for?
As you might have noticed, IDataErrorInfo.Error always returns null. Actually we did not need this property for our example. This is used in cases when you need to provide notification message to the user about validation errors. This provides you a single property which you can bind to your notification control in UI.

Note:
The issue with IDataErrorInfo is that no matter though we get the status of validation but the value is still set in the property being bound. Actually the validation logic is executed after setting the value. Though it is still useful for display of error information to the user. Before submitting the form, we still need to validate if all data is in valid state.

This is one of the validation techniques when UI has no idea about how the data should be validated.

WPF Validation - ValidateValueCallback

This is a series of discussions about different validation options in WPF. In this discussion, we will be discussing about validation through dependency property's ValidateValueCallback method.

What is ValidateValueCallBack
It is the default validation applied to a dependency property. Whenever the property value is set, the WPF runtime checks its value using this. If this is a valid value then this method should return true otherwise it should return false.

How to specify ValidateValueCallBack?
This is specified at the same time when we are registering the property with WPF runtime. It is one of the parameter of Register static method in DependencyProperty class.

What actually happens at the background?
When the dependency property is set with a value which has decided to be an invalid value in the ValidateValueCallback then it returns false. Whenever WPF runtime finds it false it results in an exception. If ValidatesOnException is set as true when the control's property is bound then the control is set with Error template.

Simple Example:
Let us create a small WPF window as follows:
<Window x:Class="wpf_validation.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<TextBox Height="23" Margin="12,19,12,0" Name="textBox1" VerticalAlignment="Top" >
<Binding Path="Name" UpdateSourceTrigger= "PropertyChanged"
ValidatesOnExceptions="True">
</Binding>
</TextBox>
</Grid>
</Window>

As you can see that we have bound Text property of textBox1 text box with Name property of data context. The other thing worth noticing is setting ValidatesOnExceptions as true.

Now have a look at the code behind of this window. In the constructor, we are setting Window2ViewModel as the data context.
public partial class Window2 : Window
{
Window2ViewModel _vm;
public Window2()
{
InitializeComponent();
_vm = new Window2ViewModel();
this.DataContext = _vm;
}
}

The definition of Window2ViewModel is as follows:
class Window2ViewModel : DependencyObject
{
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Window1ViewModel), null, new ValidateValueCallback(isNameValid));

private static bool isNameValid(object value)
{
bool ret = true;
string val = (string)value;

if (!string.IsNullOrEmpty(val) &&
System.Text.RegularExpressions.Regex.IsMatch(val, "[/!@#?/}[}{]"))
ret = false;
else
ret = true;

return ret;
}

}

So we have a dependency property, named Name in the view model. While registering this property we have specified the ValidateValueCallback method as isNameValid method. You can notice that as the dependency property isNameValid is also static in nature. We are checking the value being set for having some special character. If it contains some invalid character then it returns false. As we discussed above if binding is set with ValidatesOnException as true then the user is shown with error template on the control. In our case, if we enter any special character in the text box, it is displayed as follows:



Note:
This technique for validation is specially useful when the user interface has no idea about any validation logic. The validation is the responsibility of whatever is set as data context (in this case view model). As you might have notice when we change the validation logic, we just change it in the Window2ViewModel. This is specially useful when the data context is available in the form of libraries. The data context library providers can make sure that no invalid value is set in any property.

Friday, July 16, 2010

WPF Validation - Using Validation Rules

Who would not agree if we say that WPF binding is greatest across all technologies. But equally important is the validation of data entered by the user. Developers always get confused how they should be validating the data. In the series of discussion, including this one and following discussions, we will be discussing about different validations options in WPF. We will also discuss the specific situations in which any particular technique makes more sense.

1. Validation Rules:
This is the most simplest of all validation options available in WPF. Generally these rules are defined for individual fields.

Let us create a Window, named Window1.
<Window x:Class="wpf_validation.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:wpf_validation"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBox Height="25" Margin="6,14,26,0" Name="textBox1" VerticalAlignment="Top" >
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:SpecialCharactersRule />
</Binding.ValidationRules>
</Binding>
</TextBox>
</Grid>
</Window>

The code behind of this Window is as follows:
public partial class Window1 : Window
{
Window1ViewModel _vm;
public Window1()
{
InitializeComponent();
_vm = new Window1ViewModel();
this.DataContext = _vm;
}
}

Here we have created an instance of View Model (Window1ViewModel) and assigned it as data source of the window. We have data bounded the single text box on the window with the Name property of the data context. We also have specified SpecialCharacterRule as the validation rule for this binding. The View Model is as follows:
public class Window1ViewModel : DependencyObject
{
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Window1ViewModel));
}

The validaton rule (SpecialCharacterRule) is presented as below:
public class SpecialCharactersRule : System.Windows.Controls.ValidationRule
{
public override System.Windows.Controls.ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
System.Windows.Controls.ValidationResult validationResult;
string val = (string)value;

//if field is null / empty or contains some special characters, fail validation
if (!string.IsNullOrEmpty(val) &&
System.Text.RegularExpressions.Regex.IsMatch(val, "[/!@#?/}[}{]"))

validationResult = new ValidationResult(false, "The value contains invalid characters");
else
validationResult = new ValidationResult(true, null);

return validationResult;
}
}

This is the most simple case of validation when MVVM is used. We have separated our code in three different parts. One part is the Window itself (Window1) which not only binds its properties to the View Model (Window1ViewModel) but also defines validation rules to be used for its different fields, like SpecialCharacterRule for the text box. If the validation rule evaluates to false, the validation is considered failed. The fields is shown with the default validation adorner template.



You can notice that as soon as we enter "/" in the text box, the validation fails and the default adorner is applied to the text box. This is basically because we have specified UpdateSourceTrigger="PropertyChanged", which not only keeps copying the entered text to the data context object but also keeps on applying validation logic with each change. Basically If we need to change the validation logic for this text box, we just need to modify the validation rule.

Note:
Defining validation rules provide reusability if same validation rules are applied for more than one fields within the same form or application or even across different applications. It also provides separation of concern because a view has no knowledge how bound data would be validated. It results in light weight views as you might have noticed the code behind of the view (we just provided the context in the constructor. It provides ease of maintenance (both corrective and adaptive) because when you need to change the business rules for changing business requirements then you just need to update these validation rules.

Sunday, July 11, 2010

Using ICommand for light weight Views in WPF

Routed Commands seems to be great. But as far as writing code on the view is concerned, it seems it doesn't help us making our views more light weight (we still need to provide the definition of CanExecute() and Execute() in our view. As they are on the view, it is not easy to unit test the logic being executed.

A better approach seems to be using ICommand. ICommand allows us to provide command in accordance with Command Pattern. We know that Command Pattern suggests that Tasks should be provided in the form of Command objects and those commands should be used when those tasks need to be executed.

Let us see an example form. In this form there are two text boxes and a button. We want to copy the value of one text box to other when the button is clicked. This form would be using ViewModel and would be binding with its properties. Let us create a form which uses command based on ICommand. It expects its datacontext to provide a command property, named ProcessingCommand.

<Window x:Class="WPF_ICommand.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBox Height="23" Margin="68,15,12,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding Value1}"/>
<TextBox Height="23" Margin="68,56,12,0" VerticalAlignment="Top" Text="{Binding Value2}" />
<Label Height="28" Margin="12,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50">Value1</Label>
<Label Height="28" HorizontalAlignment="Left" Margin="12,53,0,0" VerticalAlignment="Top" Width="50">Value2</Label>
<Button Height="23" Margin="68,95,134,0" VerticalAlignment="Top" Command="{Binding ProcessingCommand}">Copy</Button>
</Grid>
</Window>


As you can see above, both text boxes are bound with some properties in the Datacontext. Button is also bound with a command in the DataContext, named ProcessingCommand. The code behind of this form is as follows:

public partial class Window1 : Window
{
Window1ViewModel _vm;
public Window1()
{
InitializeComponent();
this._vm = new Window1ViewModel();
this.DataContext = _vm;
}
}

As you can see we have used Window1ViewModel as the DataContext of the form. Now we have a look at how ViewModel (Window1ViewModel) fulfills all these expectations of Window1.

class Window1ViewModel : DependencyObject
{
public string Value1
{
get { return (string)GetValue(Value1Property); }
set { SetValue(Value1Property, value); }
}
private static DependencyProperty Value1Property =
DependencyProperty.Register("Value1", typeof(string), typeof(Window1ViewModel));

public string Value2
{
get { return (string)GetValue(Value2Property); }
set { SetValue(Value2Property, value); }
}
private static DependencyProperty Value2Property =
DependencyProperty.Register("Value2", typeof(string), typeof(Window1ViewModel));

public MyCommand ProcessingCommand {get; set;}

public Window1ViewModel()
{
this.ProcessingCommand = new MyCommand(this);
}
}

As you can see, our view model is a DependencyObject which has allowed us to register its properties Value1 and Value2 with WPF property system. We have also defined a command property named ProcessingCommand. This is the same command that we have specified with the button in the view.

Now at last, we provide the definition of the command, MyCommand.

class MyCommand : ICommand
{
#region ICommand Members

Window1ViewModel _vm;
public MyCommand(Window1ViewModel _vm)
{
this._vm = _vm;
}

bool ICommand.CanExecute(object parameter)
{
bool ret = true;
return ret;
}

event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

void ICommand.Execute(object parameter)
{
_vm.Value2 = _vm.Value1;
}

#endregion
}

In order to implement ICommand we need to implement CanExecute and Execute method. We also need to provide the EventHandler CanExecuteChanged. You can see that we are using Window1ViewModel for MyCommand to execute its task.

When we run this application. We can notice that when user writes some text in first text box and clicks Copy button then the value of first text box is copied into second text box. For doing this Execute method of MyCommand is used. You might have noticed that CanExecute method just returns true. We might have some logic which makes this task not available. In all those conditions CanExecute should return false.

Wednesday, July 7, 2010

WPF Markup Extensions

Dependency property support value resolution. For value resolution, it needs the support of Markup Extensions. May be the name of Markup Extensions is new to you but if you are familiar with WPF, you might have seen curly brackets "{}" while setting the properties. e.g.

Text = "{Binding ...}"

or

Background = "{StaticResource ...}"

Both of the examples above are the examples of application of markup extensions. Let us discuss what markup extensions are and how we can create custom markup extensions.

Namespace: System.Windows.Markup

Now let's for a moment assume a world of WPF development where there are no markup extensions (I mean no static / dynamic resource, same old way of .net binding in XAML). How difficult would it be to program in XAML? I think that is why Microsoft came up with this idea for providing an ease of development during XAML based development.

They can be used using XAML attribute and property element syntax.

Conventionally, the names of all extensions end with "Extension" but they are stripped of this when used in XAML. As you know BindingExtension is used as just "{Binding ...}".

Custom Markup Extensions:
There are situations when we need to write our own extensions. An extension is a sub class of MarkupExtension abstract class defined in System.Windows.Markup namespace. We need to implement ProvideValue method of this class in order to define a concrete extension. By going through the following lines you would realize that we can write extensions of many scenarios where the only solution, seems to be, is moving the code in code behind of the control.

Simple Example
WPF allows us to define custom extensions. A markup extension is extended from MarkupExtension abstract class defined in System.Windows.Markup namespace. For the custom extension, ProvideValue() method must be overriden. In order to define the return type of the markup extension, MarkupExtensionReturnTypeAttribute is used. Let us see the definition of our custom extension, named MyCustomExtension, below.

[MarkupExtensionReturnType(typeof(string))]
public class MyCustomExtension : MarkupExtension
{
public MyCustomExtension()
{
}

public MyCustomExtension(string txt)
{
this.SetText = txt;
}

public MyCustomExtension(string txt1, string txt2)
{
this.SetText = string.Format("{0} {1}", txt1, txt2);
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
return "Hello " + SetText;
}

string txt;
public string SetText
{
get
{
return txt;
}
set
{
txt = value;
}
}
}

You can see that we have specified string as the return type of this extension ([MarkupExtensionReturnType(typeof(string))]). The definiton of ProvideValue have also be provided. We have created a string property SetText .In addtion two constructors of this extension has been defined. This extension just include "Hello" with the text set in SetText property.

Now let us use this extension in XAML.

<Window x:Class="WPF_MarkupExtensions.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_MarkupExtensions"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBox x:Name="txtBox" Text="{local:MyCustomExtension Shujaat Siddiqi}"></TextBox>
<TextBox x:Name="txtBox2" Text="{local:MyCustomExtension SetText = Muhammad}" />
<TextBox x:Name="txtBox3">
<TextBox.Text>
<local:MyCustomExtension SetText="Siddiqi" />
</TextBox.Text>
</TextBox>
<TextBox x:Name="txtBox4" Text="{local:MyCustomExtension Muhammad, Siddiqi}"></TextBox>
</StackPanel>
</Window>

The alias of namespace containing our extension is specified as local (xmlns:local="clr-namespace:WPF_MarkupExtensions") in Window tag. We have used the extension in three different ways.

1. {local:MyCustomExtension Shujaat Siddiqi} :
This would cause single parameter constructor to be used for instantiation of the extension.

2. {local:MyCustomExtension SetText = Muhammad}:
This would cause zero arguments constructor to be used. After instantitaion it sets the SetText property as 'Muhammad'.

3.  <TextBox.Text>
<local:MyCustomExtension SetText="Siddiqi" />
</TextBox.Text>

This has exactly same behavior as 2.

4. {local:MyCustomExtension Muhammad, Siddiqi}:
This would cause the two parameter constructor to be used for instantiation of extension.

Note: It must be remembered that XAML has no way for determining the data type as it is defined in XML. So in order to select which constructor to use for instantion, it just have a look at the number of arguments. It just uses the constructor with the same number of arguments irrespective of the datatype. This puts up a limitation for constructor during runtime. The runtime gets confused about the constructor to use and results in XamlParserException. So, in order to understand this, if we add the following constructor to the definition of MyCustomExtension then while instantiation in 1st scenario, it would result in an exception.

public MyCustomExtension(int txt)
{
this.SetText = string.Format("{0}", txt);
}

Visual Studio Designer issues:
Sometimes Visual studio designer gives weird response to the custom extensions. It might include the error list with messages like:
"No constructor of type MyCustomExtension has '1' parameter"


It might not load the view in the designer:

Or it might be underlying the markup extension usage in XAML designer:

These error messages should not bother you because as soon as you run the application they are compiled fine and the application runs fine. It seems that they are just designer defects in Visual studio.

Monday, July 5, 2010

WPF Adorners

Adorner framework provides a way to decorate WPF elements with extra features. Let's start with the terminologies:

Adorner:
This is a special custom Framework element bounded to a UIElement. It is rendered in a Adorner layer which is always on top of the adorned element(s). All adorners inherit from Adorner, which is an abstract class. They must override OnRender method which is called by the layout system during rendering pass.

Namespace for Adorner: System.Windows.Documents

AdornerDecorator:
Adorner decorators provide adorner layer. This is a little funny name because 'adornment' itself means 'the act of decorating'. It provides a rendering layer for adorners.

AdornerLayer:
AdornerLayer provides rendering layer on top of the UIElement. Its placement is not affected by z-order. It is provided by using AdornerDecorator in the form.

Simple Example:
Let's see an example of usage of adorner. First we need to create an adorner.The adorner below creates a border around a UIElement. This finds out the RenderSize of the UIElement and draws a rectangle on its border. If we use DesiredSize instead, we would get the size as determined using Measure Pass which might not be the exact size as rendered.
class TextBoxBorderAdorner : Adorner
{
public TextBoxBorderAdorner(UIElement adornedElement) : base(adornedElement)
{
}

protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
base.OnRender(drawingContext);

//Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
Rect adornedElementRect = new Rect(this.AdornedElement.RenderSize);
Pen drawingPen = new Pen(new SolidColorBrush(Colors.Blue), 3);


drawingContext.DrawLine(drawingPen, adornedElementRect.BottomLeft, adornedElementRect.BottomRight);
drawingContext.DrawLine(drawingPen, adornedElementRect.TopRight, adornedElementRect.BottomRight);
}
}

Now we create a window with a text box named adornedTextBox. We have created this text box under a StackPanel defined under an AdornerDecorator (which, as discussed, would provide the adorner layer).
<Window x:Class="WPFAdornerProject.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300" Loaded="Window_Loaded">
<StackPanel HorizontalAlignment="Left" Margin="5,5,5,0">
<StackPanel>
<AdornerDecorator>
<StackPanel Orientation="Horizontal" Margin="5,5,5,0">
<Label Content="Name: " />
<TextBox x:Name="adornedTextBox" Width="200" Margin="3,3,3,3"></TextBox>
</StackPanel>
</AdornerDecorator>
</StackPanel>
</StackPanel>
</Window>

In order to apply the adorner to the textbox, we need to add the adorner to the adorner layer for the text box. This can be achieved as follows:

public Window2()
{
InitializeComponent();

//Get the adorner layer from the visual hierarchy upwards
var textBoxAdornerLayer = AdornerLayer.GetAdornerLayer(this.adornedTextBox);

//decorate text box with the adorner
textBoxAdornerLayer.Add(new TextBoxBorderAdorner(this.adornedTextBox));
}

As you can see, AdonerLayer class defines a static method, named GetAdornerLayer(). This method traverses up the visual hierarchy of the control and get the first adorner layer available (through AdornerDecorator). Later, this adorner layer is used to decorate the adornedTextBox with the defined adorner (TextBoxBorderAdorner).



As you can see, we have added a cool border to the adornedTextBox using Adorner framework.

More than one Adorner:
It seems kind of obvious requirement to allow more than one adorner to the same adorner layer. WPF does support applying them like this. They are rendered in the same adorner layer. Let's define one more adorner, which decorates the UIElement with a strikethrough line.
class TextBoxStrikeThroughAdorner : Adorner
{
public TextBoxStrikeThroughAdorner(UIElement adornedElement)
: base(adornedElement)
{
}

protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
base.OnRender(drawingContext);

Rect adornedElementRect = new Rect(this.AdornedElement.RenderSize);
Pen drawingPen = new Pen(new SolidColorBrush(Colors.Blue), 3);

Brush opacityMaskBrush = new SolidColorBrush(Colors.Yellow);
drawingContext.PushOpacityMask(opacityMaskBrush);
drawingContext.DrawLine(drawingPen, new Point(adornedElementRect.Left, adornedElementRect.Bottom - (adornedElementRect.Height / 2)), new Point(adornedElementRect.Right, adornedElementRect.Bottom - (adornedElementRect.Height / 2)));
}
}

Now we change the definition of Window2 as follows:
<Window x:Class="WPFAdornerProject.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300" Loaded="Window_Loaded">
<StackPanel HorizontalAlignment="Left" Margin="5,5,5,0">
<StackPanel>
<AdornerDecorator>
<StackPanel Orientation="Horizontal" Margin="5,5,5,0">
<Label Content="Name: " />
<TextBox x:Name="adornedTextBox" Width="200" Margin="3,3,3,3"></TextBox>
</StackPanel>
</AdornerDecorator>
<AdornerDecorator>
<StackPanel Orientation="Horizontal" Margin="5,5,5,0">
<Label Content="Grade: " />
<TextBox x:Name="adornedTextBox2" Width="200" Margin="3,3,3,3"></TextBox>
</StackPanel>
</AdornerDecorator>
</StackPanel>
</StackPanel>
</Window>
Now Window2 appears as follows:

Now we see how we can apply two adorners to the same UIElement. Let's change the Window2's constructor as follows:
public Window2()
{
InitializeComponent();

var textBoxAdornerLayer = AdornerLayer.GetAdornerLayer(this.adornedTextBox);
textBoxAdornerLayer.Add(new TextBoxBorderAdorner(this.adornedTextBox));

//Get the adorner layer
var textBox2AdornerLayer = AdornerLayer.GetAdornerLayer(this.adornedTextBox2);
//first adorner for decorating text box with border
textBox2AdornerLayer.Add(new TextBoxBorderAdorner(this.adornedTextBox2));
//second adorner for decorating text box with a strike through line
textBox2AdornerLayer.Add(new TextBoxStrikeThroughAdorner(this.adornedTextBox2));
}

I was expecting something like this to work but it seems that it doesn't:
textBox2AdornerLayer.Add(new TextBoxStrikeThroughAdorner(new TextBoxBorderAdorner(this.adornedTextBox2)));
This seems a bit of awkward for Adorner being a decorator (See Decorator Pattern).



You can verify that both adorners are applied to the second text box.

AdornedElementPlaceHolder:
AdornmentPlaceHolder is used when a custom error template is desired for controls in error as a result of some validation. Basically, a validation error template is defined as follows:

<ControlTemplate x:Key="ValidationErrorTemplate">
<Border BorderBrush="Blue" BorderThickness="5">
<AdornedElementPlaceholder />
</Border>
</ControlTemplate>
Here we have defined a blue border outlining the adorned element. Let us apply this template to the text box.

<TextBox Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}">
<Binding Path="Age">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox>

As you might have noticed, we will be assigning the an object to the data context having property "Age". e.g.

this.DataContext = new Student() { Age = 25 };
The example implementation of Student is as follows:

class Student : DependencyObject
{
public static DependencyProperty AgeProperty = DependencyProperty.Register("Age", typeof(int), typeof(Student));
public int Age
{
get
{
return (int)GetValue(AgeProperty);
}
set
{
SetValue(AgeProperty, value);
}
}
}
In the above example, if there is any exception to the text box in consideration then the ValidationErrorTemplate is applied. As soon as the user corrects the data, then the application of template is removed for the text box.

Automation Peers for Automation of WPF applications

We need UI to be tested for the required functionality the way it would be presented to the user. MVVM has provided us the way to test some of the functionalities through view models but we always want to test the behavior of the application as it is being used by end users. The answer is right, write some automation scripts. But how??

WPF provides us the facility to write automation tests using Automation Peer framework. The whole idea is to provide a framework for imitating the actions of actual users. It seems same as calling events directly but it is much better than that. Don’t believe me…see this!

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/1ba3696e-6ca2-48de-80df-31477c9504ce/

As I said, it is better to use UI automation. It allows behaving as being used by the real user. If the control has some associated command which can’t be executed, automation peer wouldn’t allow the behavior to run.

How does it work?
All UI automation works through three Ps (Peer, Provider and Pattern).The whole idea is to get a PATTERN object with for each control. All the automation is done using the properties and methods of this PATTERN object. For getting an automation object, we have to obtain a PEER object, depending upon the control in interest (e.g. TextBoxAutomationPeer for TextBox). The peer object provides a PROVIDER which can be used to get the required PATTERN.

WPF has provided us with different peer objects for different types of available controls. Each Peer defines GetPattern() method, which returns a pattern object depending upon the type of peer (e.g. TextBoxAutomationPeer provides a patterns which implements IValueProvider. These providers are available in UIAutomation.dll (System.Windows.Automation.Providers namespace).

Namespaces:
  1. System.Windows.Automation.Peers
  2. System.Windows.Automation.Providers

Assemblies:
- UIAutomation.dll
- PresentationCore.dll

Let's see this in Practice
Let us create a small program with the following main form:



The XAML definition of above form is as follows:

<Window x:Class="AutomationPeer.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBox Height="21" Margin="98,105,60,0" x:Name="result" VerticalAlignment="Top" />
<TextBox Margin="98,29,26,0" x:Name="operand1" Height="23" VerticalAlignment="Top" />
<TextBox Height="23" Margin="98,66,26,0" Name="operand2" VerticalAlignment="Top" />
<Label Height="24" HorizontalAlignment="Left" Margin="16,27,0,0" Name="label1" VerticalAlignment="Top" Width="76">Operand 1</Label>
<Label Height="24" HorizontalAlignment="Left" Margin="16,66,0,0" Name="label2" VerticalAlignment="Top" Width="76">Operand 2</Label>
<Label Height="24" HorizontalAlignment="Left" Margin="16,105,0,0" Name="label3" VerticalAlignment="Top" Width="76">Result</Label>
<Button Height="23" HorizontalAlignment="Left" Margin="17,0,0,104" Name="btnEvaluate" VerticalAlignment="Bottom" Width="75" Click="btnEvaluate_Click">Evaluate</Button>
</Grid>
</Window>

Where the definition of Click event of btnEvaluate (btnEvaluate_Click) is as follows:

private void btnEvaluate_Click(object sender, RoutedEventArgs e)
{
double operand1Value = double.Parse(operand1.Text);
double operand2Value = double.Parse(operand2.Text);

double resultValue = operand1Value + operand2Value;

result.Text = string.Format("{0}", resultValue);
}

In this event, we are getting the values entered in two boxes and adding them. We are displaying result in text block (result). Now let us create the real automation by modifying the constructor of Window1 as follows:

public Window1()
{
InitializeComponent();

var peerOperand1 = new TextBoxAutomationPeer(this.operand1);
var providerOperand1 = (IValueProvider)peerOperand1.GetPattern(PatternInterface.Value);
providerOperand1.SetValue("5.3");

var peerOperand2 = new TextBoxAutomationPeer(this.operand2);
var providerOperand2 = (IValueProvider)peerOperand2.GetPattern(PatternInterface.Value);
providerOperand2.SetValue("2.1");


var peerEvaluator = new ButtonAutomationPeer(this.btnEvaluate);
var providerEvaluator = (IInvokeProvider)peerEvaluator.GetPattern(PatternInterface.Invoke);
providerEvaluator.Invoke();
}

Here we have ValuePattern of two text boxes (operand1 and operand2) using IValueProvider provider obtained through TextBoxAutomationPeer. Finally we have obtained InvokePattern for btnEvaluate using IInvokeProvider and ButtonAutomationPeer.

When we run the application, the form displays as follows:



The form has displayed the exact result in the text block after executing the btnEvaluate_Click event for btnEvaluate method.

Automating Custom Controls:
In order to automate custom controls, we would need to define new peers. We will be discussing the details of defining user defined peers later.

Automating from outside:
In above discussion, we have seen how to automate the form from within it. Now the problem is when we want to do this automation from outside the form in our test scripts. Do we need to make our controls public? No!!!

WPF allows us to navigate through the peer hierarchy using GetChildren() and GetParent() methods. In order to automate the control, we need to traverse through this hierarchy to the concerned control and automate that. All the automation peers may provide the definition of GetChildrenCore() so that peer system could generate this peer navigation hierarchy. The default definition in UIElementAutomationPeer traverses through the visual tree of elements.

Now we deep dive a bit in the world of Automation Peer. Let's look at the class hierarchy.

Inheritance Hierarchy of Automation Peers:



All control automation peer inherit from FrameworkElementAutomationPeer directly (like TextBlockAutomationPeer) or indirectly (like ButtonAutomationPeer through ButtonBaseAutomationPeer).

Let's play again:
Now we provide the same automation to the form from outside the form. Let's remove the automation code from constructor of Window1. Now it should look like as follows:

public Window1()
{
InitializeComponent();
}

In order to keep the example simple to understand, We are not creating a separate project. Modify App.xaml as follows:

<Application x:Class="AutomationPeer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup"
>
<!--StartupUri="Window1.xaml"-->
<Application.Resources>

</Application.Resources>
</Application>


Now let's provide implementation for Application_Startup event.

private void Application_Startup(object sender, StartupEventArgs e)
{
ProgramAutomation pAutomation = new ProgramAutomation();
pAutomation.automate()
}


Where ProgramAutomation is defined as follows:

class ProgramAutomation
{
public ProgramAutomation()
{
}

public void automate()
{
var myWindow1 = new Window1();

//It is required that a window is available on UI before calling GetChildren on it
myWindow1.Show();

var myWindow1AutomationPeer = new WindowAutomationPeer(myWindow1);
var myWindow1AutomationPeerChildres = myWindow1AutomationPeer.GetChildren();

//get automation peers of operands text boxes and button
var operand1AutomationPeer = myWindow1AutomationPeerChildres[1]; //myWindow1AutomationPeerChildres.Where(p => p.GetName() == "operand1").FirstOrDefault();
var operand2AutomationPeer = myWindow1AutomationPeerChildres[2]; //.Where(p => p.GetName() == "operand2").FirstOrDefault();
var evaluatorAutomationPeer = myWindow1AutomationPeerChildres[6];//.Where(p => p.GetName() == "btnEvaluate").FirstOrDefault();
var resultAutomationPeer = myWindow1AutomationPeerChildres[0];

((IValueProvider)((TextBoxAutomationPeer)operand1AutomationPeer).GetPattern(PatternInterface.Value)).SetValue("5.3");
((IValueProvider)((TextBoxAutomationPeer)operand2AutomationPeer).GetPattern(PatternInterface.Value)).SetValue("2.1");
((IInvokeProvider)((ButtonAutomationPeer)evaluatorAutomationPeer).GetPattern(PatternInterface.Invoke)).Invoke();
string result = ((IValueProvider)((TextBoxAutomationPeer)resultAutomationPeer).GetPattern(PatternInterface.Value)).Value;
System.Windows.MessageBox.Show(result);
}
}


Now as you might have an idea from the code that we are setting the values of the two operands as before. After invoking the button event, we are getting value of result text box. The message box should show 7.4 on the screen. But it doesn't. Why??

It must be remembered that IInvokeProvider allows an event to be fired, which is asynchronous. It just sends a request to execute its action. It doesn't guarantee when it would be invoked. That is why the message box is always empty because the invoke is executed after we execute the following:

string result = ((IValueProvider)((TextBoxAutomationPeer)resultAutomationPeer).GetPattern(PatternInterface.Value)).Value;

The only solution seems to be invoking the action on a separate thread using dispatcher and waiting for it to return using Thread.join.

Otherwise, just display an empty message box to the user. This is a blocking call as the runtime has to wait for user action. In the mean time, it executes the Invoke(). The new definition of automate() is as follows:

public void automate()
{
var myWindow1 = new Window1();

//It is required that a window is available on UI before calling GetChildren on it
myWindow1.Show();

var myWindow1AutomationPeer = new WindowAutomationPeer(myWindow1);
var myWindow1AutomationPeerChildres = myWindow1AutomationPeer.GetChildren();

//get automation peers of operands text boxes and button
var operand1AutomationPeer = myWindow1AutomationPeerChildres[1];
var operand2AutomationPeer = myWindow1AutomationPeerChildres[2];
var evaluatorAutomationPeer = myWindow1AutomationPeerChildres[6];
var resultAutomationPeer = myWindow1AutomationPeerChildres[0];


((IValueProvider)((TextBoxAutomationPeer)operand1AutomationPeer).GetPattern(PatternInterface.Value)).SetValue("5.3");
((IValueProvider)((TextBoxAutomationPeer)operand2AutomationPeer).GetPattern(PatternInterface.Value)).SetValue("2.1");
((IInvokeProvider)((ButtonAutomationPeer)evaluatorAutomationPeer).GetPattern(PatternInterface.Invoke)).Invoke();

System.Windows.MessageBox.Show("");
string result = ((IValueProvider)((TextBoxAutomationPeer)resultAutomationPeer).GetPattern(PatternInterface.Value)).Value;
System.Windows.MessageBox.Show(result);
}