This is the next sample in the WPF Sample Applications Series. The purpose of the Sample Series is to provide concise code solutions for specific programming tasks. This sample provides a brief description of the problem, the solution and full source code.
Yesterday I was working on a Validation Summary control similar to the ASP.NET Validation Summary for my WPF business applications. I wanted to use the Expander control to display the validation errors to the user. So I dove in, and quickly realized that the Expander control doesn’t have built in behavior to overlay other controls when I expands.
I searched the web, reviewed my WPF books, viewed example code for an hour but couldn’t find what I was looking for. To make sure I wasn’t missing something I even rang up a great friend and WPF expert to confirm this is the standard Expander control behavior.
There are several solutions for this problem. You could restyle other WPF controls that have dropdown overlay capabilities built in, could use a PopUp control or you could load up a ToolTip with the information.
I like the Expander control and wanted to use it. It remains expanded until either closed by the user or programmatically and Vista users have seen and used this control (or similar control) and know what it does and how it works.
Note: The Expander control has some specific guidelines about setting the Height or Width properties that you should read at MSDN Expander.
The solution I came up with was to wrap the Expander control in a Canvas control. The Canvas control’s Height was defined and limited by the Grid.Row Height. I could have also set the Canvas Height property and set the Grid.Row Height to Auto. I prefer the container controls to manage the layout when possible. I have tried all the WPF container controls, but only the Canvas control allows this to work as described.
When the Expander control expands, the parent Canvas will not resize. Since the Canvas control’s ClipToBounds property defaults to False, child controls are permitted to extend past the boundary of the Canvas control.
We still have one more detail to cover. How to get the Expander’s Content to overlay the controls below it and appear on top. By setting the Canvas control’s attached property, Panel.ZIndex to 99, the WPF layout system to render the Canvas and it’s child controls on top of other controls that have a lower Panel.ZIndex property values. Presto, we have an Expander control that over lays controls below it.
Getting the Expander control Content to look like a real PopUp window or ToolTip is super easy in WPF. I added a DropShadowBitmapEffect to Grid control that lays out the Expander control’s expanded content.
After downloading, you must rename the following download by changing the file extension from .doc to .zip. This is a requirement of WordPress.com.
Here are the bullet points of this solution:
- Wrap the Expander control inside a Canvas control.
- Constrain the Canvas height to the desired height when the Expander control is collapsed.
- Set the Canvas Panel.ZIndex higher than controls you want to overlay.
- Style and design your Expander Content so that it looks like a PopUp.
<Window x:Class="Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Expender WPF Sample" Height="300" Width="400" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Expander HorizontalAlignment="Left" Header="Standard Expander" VerticalAlignment="Top" ExpandDirection="Down" Width="150"> <TextBlock TextWrapping="Wrap" Background="AntiqueWhite"> This is the standard expander behavior. The expander opens and the controls below it move down. </TextBlock> </Expander> <StackPanel Grid.Row="1" Margin="10,5,0,0"> <RadioButton Content="Choice One"/> <RadioButton Content="Choice Two"/> <RadioButton Content="Choice Three"/> </StackPanel> </Grid> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="33" /> <RowDefinition /> </Grid.RowDefinitions> <Canvas Panel.ZIndex="99"> <Expander HorizontalAlignment="Left" Header="PopUp Window Expander" VerticalAlignment="Top" ExpandDirection="Down" Width="175"> <Grid Background="Cornsilk"> <Grid.BitmapEffect> <DropShadowBitmapEffect /> </Grid.BitmapEffect> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <TextBlock Text="How Cool Is This!" FontWeight="Bold" Margin="5"/> <TextBlock Grid.Row="1" TextWrapping="Wrap" Margin="5"> This is the popup expander behavior. The expander opens and overlays the controls below it. </TextBlock> </Grid> </Expander> </Canvas> <StackPanel Grid.Row="1" Margin="10,5,0,0"> <RadioButton Content="Choice One"/> <RadioButton Content="Choice Two"/> <RadioButton Content="Choice Three"/> </StackPanel> </Grid> </Grid> </Window>
Hope you can learn just a little bit more about WPF from this article and the Sample Series.
Just a grain of sand on the worlds beaches.