We all know how sucky WPF validation is out of the box. I am trying a very simple thing and for some reason it is always failing. I have a TextBox and my only requirement is to validate that the user inputs something in the TextBox. The TextBox is bound to a Customer object with FirstName and LastName properties.
Here is the XAML code:
<TextBox Style="{StaticResource TextBoxStyle}" Grid.Column="1" Grid.Row="0" Height="20" Width="100" Margin="10">
<TextBox.Text>
<Binding Path="FirstName" >
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Here is the Customer class FirstName property:
public string FirstName
{
get { return _firstName;}
set
{
if(String.IsNullOrEmpty(value))
throw new ApplicationException("FirstName cannot be null or empty!");
_firstName = value;
OnPropertyChanged("FirstName");
}
}
Even though I am throwing an exception if the FirstName (value) is null or empty it is only handled if I type something in the TextBox and then delete it and then tab off. The reason is that it is dependent on the property changed event. But even if I put that TextBox binding on Focus it does not fire the validation.
UPDATE:
One of the ugliest ways to handle this issue is to assign the String.Empty to the TextBoxes on the Window.Loaded event:
void AddCustomerWindow_Loaded(object sender, RoutedEventArgs e)
{
// get all the textboxes and set the property to empty strings!
txtFirstName.Text = String.Empty;
txtLastName.Text = String.Empty;
}
Here is the code for binding:
public AddCustomerWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(AddCustomerWindow_Loaded);
gvAddCustomer.DataContext = new Customer();
}
Best Answer
The solution I use is to wire-up the controls to update their own binding sources whenever they lose focus. This makes the controls validate after the user has tabbed or clicked through them once.
If you also want the controls to validate on load - i.e., before the user tabs/clicks through them - then you could write an UpdateSourceNow method similar to the one above, and call it from AddCustomerWindow_Loaded instead.
However, I prefer to wait until each control is visited, because it can be somewhat alarming to users if they immediately see a screen full of red boxes when they want to enter a new Model object instance.