views:

1178

answers:

3

Hi,

I'm doing some validation on the DataSource of TextBox that's within an Expander and have found that once a validation error has been triggered, if I collapse the Expander, the red box stays where the TextBox would have been.

<Expander Header="Blah Blah Blah">
  <TextBox Name="TextBox"
           Validation.ErrorTemplate="{DynamicResource TextBoxErrorTemplate}"
           Text="{Binding Path=Blah,
                          UpdateSourceTrigger=PropertyChanged,
                          ValidatesOnDataErrors=True}" />
</Expander>

I've tried to get round this by binding the visibility of the Error Template to the Expander, however I think there's something wrong with the binding.

<local:NotVisibleConverter x:Key="NotVisibleConverter" />

<ControlTemplate x:Key="TextBoxErrorTemplate">
  <DockPanel>
    <Border BorderBrush="Red" BorderThickness="2" 
            Visibility="{Binding Path=IsExpanded, 
                                 Converter={StaticResource NotVisibleConverter}, 
                                 RelativeSource={RelativeSource AncestorType=Expander}}" >
      <AdornedElementPlaceholder Name="MyAdorner" />
    </Border>
  </DockPanel>
  <ControlTemplate.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
        <Setter Property="ToolTip"
                Value="{Binding RelativeSource={RelativeSource Self}, 
                                Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

I guess I've gone wrong with my binding, can someone put me back on track please? Alternatively does anyone know another solution to the ErrorTemplate still being visible on the collapse of an Expander?

+9  A: 

Rather than doing any binding, you could place an AdornerDecorator around the elements inside of your expander. You see, the validation error template is placed on the adorner layer that way it shows up on top of everything else. That's ultimately what your problem is. Even though your text box is not visible because the expander is closed, the error template is still on the adorner layer.

I believe you can fix this with the following xaml:

<Expander Header="Blah Blah Blah">
   <AdornerDecorator>
      <TextBox Name="TextBox"
               Validation.ErrorTemplate="{DynamicResource TextBoxErrorTemplate}"
               Text="{Binding Path=Blah,
                              UpdateSourceTrigger=PropertyChanged,
                              ValidatesOnDataErrors=True}" />
   </AdornerDecorator>
</Expander>

This creates an adorner layer specifically for within the expander. When the expander is closed the AdornerDecorator also gets hidden and so should everything on it.

-- HTH, Dusty

dustyburwell
@Dusty -- nice answer. I'm going to try this as I have a similar issue in my app. Does the `AdornerDecorator` affect the layout at all? +1
Drew Noakes
The AdornerDecorator should not affect layout. It's just a wrapper around a child.
dustyburwell
Ok, so it can be thought of as preserving the layout but lifting the rendering and interaction of its child to the adorner layer? I thought there was only one adorner layer, but the way you've phrased the answer suggests it makes a new layer.
Drew Noakes
Thanks for the help, this has worked a treat!
Andy Clarke
@Drew Sorry, I didn't mean to confuse. No, it doesn't lift the child to the adorner layer. It does effectively create another adorner layer. The new adorner layer is used for adorners created on anything in the visual tree below the AdornerDecorator. Typically, yes, there is only one adorner layer, created on the Window. I think the default ControlTemplate for the Window class has an AdornerDecorator. No magic here.
dustyburwell
A: 

In general, debugging bindings can be done by:

  1. Sticking breakpoints in a converter (if you're using one, which you are)
  2. Checking the Output pane in Visual Studio for any debug warnings about invalid bindings

In the code you've posted, I believe it's going to be because the Value property on Setter is not a dependency property and therefore cannot be bound to.

I'll have a think about this and see if I can come up with something more helpful.

Drew Noakes
+1  A: 

Check out Donnelle's answer at http://stackoverflow.com/questions/321327/how-do-i-get-rid-of-the-red-rectangle-when-my-wpf-binding-validation-has-failed-a. It worked for me with the expander.

Kevin