The downloadable sample code contains a number of examples of asynchronous input validation. The simplest is located in the AsyncValidationViewModel
class.
The AsyncValidationView
contains two string properties that are required to be non-null or whitespace strings (see Figure 26.12).
When either of the two properties is set to an empty or whitespace string, a data validation error is created for that property. This validation occurs when the user modifies the text or when the Submit button is tapped (see Figure 26.13).
The two TextBox
controls are each bound to a property in the viewmodel, as shown in the following excerpt:
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,60,12,0">
<TextBlock Text="Validated String 1"
Style="{StaticResource PhoneTextTitle3Style}" />
<TextBox Text="{Binding ValidatedString1, Mode=TwoWay,
NotifyOnValidationError=True}"
Style="{StaticResource ValidatingTextBoxStyle}" />
<TextBlock Text="Validated String 2"
Style="{StaticResource PhoneTextTitle3Style}" />
<TextBox Text="{Binding ValidatedString2, Mode=TwoWay,
NotifyOnValidationError=True}"
Style="{StaticResource ValidatingTextBoxStyle}" />
<StackPanel Orientation="Horizontal">
<Button Content="Submit"
Command="{Binding SubmitCommand}"
Width="144" Height="75" HorizontalAlignment="Left" />
<controls:ValidationSummary />
</StackPanel>
<TextBlock Text="{Binding Message}"
Style="{StaticResource PhoneTextNormalStyle}" />
</StackPanel>
The submit Button
is bound to the viewmodel’s SubmitCommand
. The SubmitCommand
is instantiated in the constructor of the AsyncValidationViewModel
class, as shown in the following excerpt:
public AsyncValidationViewModel()
{
AddValidationProperty(() => ValidatedString1);
AddValidationProperty(() => ValidatedString2);
submitCommand = new DelegateCommand(
delegate
{
IsComplete(
() => Message = "Data Submitted!",
() => Message = string.Empty,
obj => Message = "An error occured: " + obj.Message);
});
}
When the button is pressed, the SubmitCommand
calls the IsComplete
method of the ViewModelBase
class, which calls the DataErrorNotifier.IsComplete
method with the same signature. Recall that the IsComplete
method has the following three parameters:
An Action
to perform if there are no validation errors.
An Action
to perform if there are validation errors.
A Func
to perform if an exception is raised and the validation process fails.
The IsComplete
method causes the overridden BeginValidation
method of the AsyncValidationViewModel
class to be called. Asynchronous behavior is simulated by calling a private Validate
method using a thread from the ThreadPool
. In a less trivial application, we could imagine that this call could be to a web service, for example.
public override void BeginValidation(string memberName, object value)
{
try
{
/* Perform validation asynchronously. */
ThreadPool.QueueUserWorkItem(state => Validate(memberName, value));
}
catch (Exception ex)
{
OnValidationComplete(
new ValidationCompleteEventArgs(memberName, ex));
}
}
As previously stated, it is imperative that the ValidationComplete
event is raised no matter what the outcome of the validation activity. Therefore, the validation logic is wrapped in a try-catch block, so that if an exception occurs, the ValidationComplete
event is still raised, as shown in the following excerpt:
void Validate(string propertyName, object value)
{
try
{
IEnumerable<DataValidationError> errors
= GetPropertyErrors(propertyName, value);
if (errors != null && errors.Count() > 0)
{
OnValidationComplete(
new ValidationCompleteEventArgs(propertyName, errors));
}
else
{
OnValidationComplete(
new ValidationCompleteEventArgs(propertyName));
}
}
catch (Exception ex)
{
OnValidationComplete(
new ValidationCompleteEventArgs(propertyName, ex));
}
}
If either of the viewmodel’s string properties fails validation, a DataValidationError
for the property is added to the list of validation errors for that property.
18.221.103.229