I'm trying to implement WPF validation on a few text boxes. I want to be able to display the validation errors to the user with something more obvious than a tool-tip, but more subtle than a dialog or messagebox. I settled on using the Popup class, rather than some built in textbox for displaying errors, since there are many different fields that need to be validated this way, and I want the feedback to be "attached" to the field in question.
The problem I'm experiencing is that the binding of the Popup's child TextBox to the attached TextBox's (Validation.Errors) property is not updated aggressively enough. As soon as there is an Error object, the text is updated and displayed (i.e. "Please enter a name." for an empty field) but if the error changes (i.e. the user enters invalid text) the message in the popup stays the same... until/unless they enter valid input, at which point the popup disappears as desired.
I've done some debugging, and I've found that while the validation rule is being called correctly and returning the proper results, the converter for the Popup is only called at the creation of the initial error. I guess what I am confused about is why the Popup gets updated only when the validation state goes from "no errors" to "some error(s)", so to speak. Does anyone know a way to force the changes to Validation.Errors to be reflected in my Popup's TextBox.Text?
Here's a xaml example of what I've written.
<TextBox Name="MyTextBox">
<TextBox.Text>
<Binding Path="MyText" UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<local:MyTextBoxValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Popup Name="MyPopup" IsOpen="{Binding ElementName=MyTextBox,
Path=(Validation.HasError), Mode=OneWay}">
<Border BorderThickness="1" BorderBrush="Red" Background="White">
<T开发者_如何转开发extBlock Foreground="Red" Margin="5 5 5 5"
Text="{Binding ElementName=MyTextBox, Path=(Validation.Errors),
Converter={StaticResource errorsToMessageConverter}}"/>
</Border>
</Popup>
I was able to find a compromise. I changed the binding on the Popup's TextBlock like so:
<TextBlock Name="MyPopupTextBox" Foreground="Red" Margin="5 5 5 5"
Text="{Binding ElementName=MyTextBox, Path=(Validation.Errors)[0].ErrorContent,
UpdateSourceTrigger=PropertyChanged, Mode=OneWay, NotifyOnValidationError=True,
NotifyOnSourceUpdated=True, ValidatesOnExceptions=True}"/>
Your original problem is a typical problem when binding to a collection: As long as your collection does not change structurally (insert/remove/clear), the binding will not see any reason to update. So if only an item in the collection changes some property, this does not cause your binding to update.
You have already solved this by binding to the element in this collection, this way the full path to the changed property (the ErrorContent) will be observed in the binding.
The problem with binding (Validation.Errors)[0]
is that it raises IndexOutOfRange-Exceptions (not thrown, but they are there) if the Error-Collection is empty.
This thread discusses that exception and also contains a workaround that works fine for me:
http://social.msdn.microsoft.com/forums/en/wpf/thread/1c6cd214-abce-4a8b-a919-0726dd81461a/
Just replace (Validation.Errors)[0].ErrorContent
by (Validation.Errors).CurrentItem.ErrorContent
and you are done.
精彩评论