I’m having issues with a WPF Expander that I have in a user control that gets rendered in a ListBox. Essentially I’m trying to get PopUpButton behavior on each ListItem in my ListBox. When I open the Expander the content is rendering behind everything else as if it were transparent, or lower in the z-order. I’ve tried this with a WPF PopUp and Toggle Button as well (using techniques described int Karle Shivllet’s blog – Expander Control with Popup Content) to no avail.
Let me first describe what it is I’m trying to do. I have two controls that display a list of inputs that I need to configure for my application. For simplicity sake, one user control is used to configure inputs to a graph, and another control is used to control inputs to a simple excel grid. The inputs for the graph and grid each have properties that need to be configured on them. I’ve developed a simple user control called InputSelectControl that will render a ListBox containing the list of inputs to be configured for the graph or grid. Each ListItem in the ListBox consist of a TextBlock for the input’s name (e.g. Pressure, ECG, etc.) and a WPF Expander that , when clicke, displays a property editor for that input. Since the property editor presentation will be different depending on whether I’m dealing with graph inputs versus grid inputs, I’ve used a DependencyProperty on my InputSelectControl that is of type ControlTemplate. This allows my grid and graph to each supply the presentation they need for editing their input properties. Also note that I will have more than just a graph and a grid that need this behavior, thus the desire to make this a user control that can dynamically receive presentation behavior.
I’ve tried placing my Expander inside my property editor template, had have also tried experimenting with the ZIndex in various places, but always end up with the same behavior, the Expander popup displays behind the ListItems in my list.
Below is some code further describing my approach. Hopefully someone can help me out of this pickle.
XAML representing my Grid (could be graph, or something else) control that hold my InputSelectControl:
<UserControl x:Class="MyApp.GridView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:props="clr-namespace:PopupButtonDependencyProp" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<!-- Specify the control tempalte we want loaded into the
properies popup for a grid-->
<ControlTemplate x:Key="GridPropertyEditorTemplate" TargetType="ContentControl">
<props:GridInputPropertyEditor />
</ControlTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Hello Grid" Margin="5" />
<!-- Tell the InputSelectControl what template to load into Property
Window for each Grid Input item -->
<props:InputSelectControl Grid.Row="1"
DataContext="{Binding VmUsedInputs, Mode=OneWay}"
PropertyEditorTemplate="{StaticResource GridPropertyEditorTemplate}" />
</Grid>
</UserControl>
XAML representing my InputSelectControl that displays my list of inputs and a ContentControl place holder for each ListItem where I want my “Popup behavior” for editing properties:
<UserControl x:Class="MyApp.InputSelectControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:props="clr-namespace:PopupButtonDependencyProp"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<!-- Listbox holding our inputs. Assuming whatever we're contained in has
set our DataContext to a valid Input collection-->
<ListBox x:Name="inputsUsed" Grid.Row="1" ItemsSource="{Binding}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionMode="Multiple" ClipToBounds="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Border x:Name="border" CornerRadius="7">
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal">
<!-- Input label-->
<TextBlock Text="{Binding Path=Label}" FontWeight ="Bold"
FontSize ="12" FontStyle = "Normal"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="5,0,5,0" />
<Expander x:Name="GridPropEditor" Header="Properties"
Height="Auto" Margin="5,0,0,0"
ToolTip="Open trace property dialog">
<!-- Properties button - The ContentControl below is rendering
the PropertyEditorTemplate that was set by whoever contains us -->
<ContentControl Template="{Binding PropertyEditorTemplate,
RelativeSource={RelativeSource AncestorType=props:InputSelectControl}}" />
</Expander>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
C# representing my DependencyProperty for injection the property editor template to present on popup.
/// <summary>
/// Interaction logic for InputSelectControl.xaml
/// </summary>
public partial class InputSelectControl : UserControl
{
#region Dependency Property stuff
/// <summary>
/// Dependency Property for control template to be rendered. This
/// lets us adorn the InputSelectControl with content in the Xaml.
/// The content can be different fore each instance of InputSelectControl.
/// </summary>
public static DependencyProperty PropertyEditorTemplateProperty =
DependencyProperty.Register("PropertyEditorTemplate",
typeof(ControlTemplate), typeof(InputSelectControl));
/// <summary>
/// PropertyEditorTemplate. This is how the property is set and get by WPF
/// </summary>
public ControlTemplate PropertyEditorTemplate
{
get { return GetValue(PropertyEditorTemplateProperty) as ControlTemplate; }
set { SetValue(PropertyEditorTemplateProperty, value); }
}
#endregion
/// <summary>
/// Constructor
/// </summary>
public InputSelectControl()
{
InitializeComponent();
}
}
XAML representing my GridInputPropertyEditor which is the template describing the presentation for editing Grid properties. This will be different for a Graph:
<UserControl x:Class="MyApp.GridInputPropertyEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Canvas Panel.ZIndex=”99”>
<!-- Property Editor Control - Assumes DataContext holds to the properties
that need to be edited-->
<StackPanel Orientation="Vertical" Background="WhiteSmoke">
<!-- Lists the properties for a Grid to be edited. We could use
any layout we need here. -->
<ListBox ItemsSource="{Binding Properties}" Background="WhiteSmoke" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="5,5">
<TextBlock Text="{Binding Label}" FontWeight="Bold"/>
<TextBlock Text=":" />
<TextBox Text="{Binding Value}" Margin="10,0" Width="20" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Canvas>
</UserControl>
Using Snoop I was able to figure out that if I set the Z-Index of the ListBox item to a high number my property editor comes to the foreground. If someone sees a better way around this let me know. Otherwise I could use some help coming up with a trigger to raise and lower the zindex based on the item selected.
Okay, after a few trials and tribulations I was able to come up with solution using code behind. I’d be interested in finding a way to do this with triggers, but I’m not sure it’s possible with this approach.
Here’s the update expander XAML:
Here’s the code behind I added to my xaml.cs file
The code behind solution closes any expanders that might already be opened and brings the currently expanding Expanders container to the foreground by setting the zindex to 99.
Again, if anyone has a better solution I’m all ears.