Windows Phone 7 Validation

Today I downloaded Windows Phone 7 SDK to look how much it is different from Silverlight on desktops and from Android OS development. I created a simple form and decided to implement validation, so I went to google and started to search how it is implemented by other people.

Unfortunately, there was very little information about it: the search results page contained lots of irrelevant results like “windows phone activation key” and other strange words. The answers from StackOverflow.com also weren’t ideal: they recommended to use exceptions inside properties or create a custom control inherited from TextBox and create a bunch of properties.

That’s why I’ve decided to spend my time and to write a post how the validation can be implemented with little efforts.
My validation will be based on the INotifyDataErrorInfo interface and I’ll use the validation classes which I developed for WPF and Silverlight here.

Here is the screenshot of the application at the end:

Page layout

At first you need to create the layout with correct bindings:

<StackPanel Grid.Row="1" Margin="12">
	<TextBlock Text="First Name:" />
	<TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" Style="{StaticResource ValidationTextBoxStyle}" />
	<TextBlock Text="Last Name:" />
	<TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"  Style="{StaticResource ValidationTextBoxStyle}" />
	<Button HorizontalAlignment="Center" Content="Save" Click="SaveButton_Click" />
</StackPanel>
  • The TwoWay binding is important, because you need to send the entered by user data back to the view model.
  • Next necessary property is ValidatesOnNotifyDataErrors, it is used because of the INotifyDataErrorInfo interface. If I used validation through exceptions, I would put the other property (ValidatesOnExceptions) inside the binding. But this interface much better than exceptions.
  • The last binding property is NotifyOnValidationError whose name is very confusing with the previous property. But the previous property is raised first and retrieves errors from the view model. The current property is raised after that and it calls the BindingValidationError event of the view.

TextBox visual feedback

Next issue which I’ve encountered is that WP7 controls don’t have build-in validation feedback. So you should create your own visual states and provide visual feedback. I’ve copied the existing style of the TextBox control by using Expression Blend and slightly changed it.
Earlier it looked so:

<ControlTemplate TargetType="TextBox">
	<Grid Background="Transparent">
		<VisualStateManager.VisualStateGroups>
			<!-- Visual States -->
		</VisualStateManager.VisualStateGroups>
		<!-- Borders -->
	</Grid>
</ControlTemplate>

I added validation states and controls:

<ControlTemplate TargetType="TextBox">
	<StackPanel Background="Transparent">
		<VisualStateManager.VisualStateGroups>
			<!-- Visual States -->
			<VisualStateGroup x:Name="ValidationStates">
				<VisualState x:Name="Valid" />
				<VisualState x:Name="Invalid" >
					<Storyboard>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationBorder">
							<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
						</ObjectAnimationUsingKeyFrames>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationMessage">
							<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
						</ObjectAnimationUsingKeyFrames>
					</Storyboard>
				</VisualState>
			</VisualStateGroup>
		</VisualStateManager.VisualStateGroups>
		<Grid>
			<!-- Borders -->
			<Border x:Name="ValidationBorder" BorderBrush="Red" BorderThickness="2" Visibility="Collapsed" Margin="6,3" />
		</Grid>
		<TextBlock x:Name="ValidationMessage" Foreground="Red" Visibility="Collapsed" Text="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}" Margin="6,0" />
	</StackPanel>
</ControlTemplate>

C# code

Than I added to the view the code which changes validation states. You should set the NotifyOnValidationError property to true in bindings so that the BindingValidationError event works.

public MainPage()
{
	InitializeComponent();

	this.DataContext = new MainViewModel();

	this.BindingValidationError += MainPage_BindingValidationError;
}

private void MainPage_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
	var state = e.Action == ValidationErrorEventAction.Added ? "Invalid" : "Valid";

	VisualStateManager.GoToState((Control)e.OriginalSource, state, false);
}

And that’s almost all. The view model class is very simple:

public class MainViewModel : ValidationViewModel
{
	public MainViewModel()
	{
		this.Validator.AddValidationFor(() => this.FirstName).NotEmpty().Show("Enter the first name");
		this.Validator.AddValidationFor(() => this.LastName).NotEmpty().Show("Enter the last name");
	}

	private string firstName;

	public string FirstName
	{
		get { return firstName; }
		set
		{
			firstName = value;
			RaisePropertyChanged("FirstName");
		}
	}

	private string lastName;

	public string LastName
	{
		get { return lastName; }
		set
		{
			lastName = value;
			RaisePropertyChanged("LastName");
		}
	}
}

The ValidationViewModel class you can take from the sample project.
You can download the source code here: WindowsPhoneValidation.zip

Advertisements

One Response to Windows Phone 7 Validation

  1. Milky says:

    Hi. i tried your code. Whenever i run my program, it will always give me this problem: Application_UnhandledException.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: