Validation in TextBox: red frame does not always display with invalid results

I have a text box that is bound to a property that requires a value, i.e.:

[Required(ErrorMessage = "required value")] public string SomeText { //get set... } 

And in my XAML, I have the following setting for my text box:

  UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true, ValidatesOnExceptions=true 

As expected, the red frame appears when there is no value in the text box, however, when I select another tab and then return to the page with invalid results, the red frame no longer appears. It appears only after entering the correct result and then deleting it.

How can I debug this? How can I find out which event causes the appearance of the red border?

+7
source share
2 answers

In WPF, when tab items are unloaded from the visual tree, the fact that they were marked as invalid is lost. Basically, when a validation error occurs, the user interface responds to an event in the validation stack and notes that the item is invalid. This marking is not reevaluated when an element is returned to the visual tree, unless the anchor is also re-evaluated (which usually does not happen if the user clicks on the tab element).

Define such a function somewhere (I put it in the static ValidationHelper class along with some other things):

 public static void ReMarkInvalid( DependencyObject obj ) { if( Validation.GetHasError( obj ) ) { List<ValidationError> errors = new List<ValidationError>( Validation.GetErrors( obj ) ); foreach( ValidationError error in errors ) { Validation.ClearInvalid((BindingExpressionBase)error.BindingInError); Validation.MarkInvalid((BindingExpressionBase)error.BindingInError, error); } } for( int i = 0; i < VisualTreeHelper.GetChildrenCount( obj ); i++ ) { ReMarkInvalid( VisualTreeHelper.GetChild( obj, i ) ); } } 

I think you can call this function in the TabControl Selected event, and it should have the desired effect. For example:.

 private void TabControl_Selected(...) { ReMarkInvalid( tabControl ); } 

If this does not work, you may need to do this with a lower dispatcher priority to ensure that the visual tree completes the download first. What would look like replacing ReMarkInvalid ... with:

 Dispatcher.BeginInvoke( new Action( delegate() { ReMarkInvalid( tabControl ); } ), DispatcherPriority.Render ); 
+8
source

You can simply put the contents of your tab in AdornerDecorator tags:

 <TabControl> <TabItem> <AdornerDecorator> <ContentControl Content="{Binding TabItemViewModel}" /> <Grid> <!-- Other Stuff --> </Grid> </AdornerDecorator> </TabItem> </TabControl> 

Update:

AdornerDecorator does not display the borders of controls that are invisible (on unselected tabs). It just keeps the borders between the tabs as soon as the borders have already been displayed.

However, the code above Dana Cartwright works fine. You just need to put ClearInvalid before MarkInvalid , as indicated by lost_bits1110:

 Validation.ClearInvalid((BindingExpressionBase)error.BindingInError); Validation.MarkInvalid((BindingExpressionBase)error.BindingInError, error); 
0
source

All Articles