У меня проблемы с WPF Expander, который есть у меня в пользовательском элементе управления, который отображается в ListBox. По сути, я пытаюсь получить поведение PopUpButton для каждого ListItem в моем ListBox. Когда я открываю Expander, содержимое отрисовывается позади всего остального, как если бы оно было прозрачным или ниже в z-порядке. Я пробовал это также с помощью всплывающих окон и переключателей WPF (используя методы, описанные в блоге Карла Шивлета - Расширение управления всплывающим контентом), но безрезультатно.
Позвольте мне сначала описать, что я пытаюсь сделать. У меня есть два элемента управления, которые отображают список входов, которые мне нужно настроить для моего приложения. Для простоты один пользовательский элемент управления используется для настройки входных данных для графика, а другой элемент управления используется для управления входными данными для простой сетки Excel. Входные данные для графика и сетки имеют свойства, которые необходимо настроить для них. Я разработал простой пользовательский элемент управления с именем InputSelectControl, который будет отображать ListBox, содержащий список входов, которые необходимо настроить для графика или сетки. Каждый элемент ListItem в ListBox состоит из TextBlock для имени входа (например, давления, ЭКГ и т. Д.) И расширителя WPF, который при щелчке мыши отображает редактор свойств для этого ввода. Так как представление редактора свойств будет отличаться в зависимости от того, имею ли я дело с входными данными графика и входными данными сетки, я использовал DependencyProperty в моем InputSelectControl, который имеет тип ControlTemplate. Это позволяет моей сетке и графику предоставлять каждому представление, необходимое для редактирования их входных свойств. Также обратите внимание, что у меня будет больше, чем просто график и сетка, которые нуждаются в этом поведении, поэтому я хочу сделать это пользовательским элементом управления, который может динамически получать поведение представления.
Я пытался поместить свой Expander в свой шаблон редактора свойств, также пытался экспериментировать с ZIndex в разных местах, но всегда получал одно и то же поведение, всплывающее окно Expander отображается позади ListItems в моем списке.
Ниже приведен код, описывающий мой подход. Надеюсь, кто-то может помочь мне выбраться из этого рассола.
XAML, представляющий мой элемент Grid (может быть граф или что-то еще), который содержит мой 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, представляющий мой InputSelectControl , который отображает мой список входных данных и заполнитель ContentControl для каждого ListItem, где я хочу, чтобы мое "поведение всплывающего окна" для редактирования свойств:
<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 #, представляющий мой DependencyProperty для внедрения шаблона редактора свойств для представления во всплывающем окне.
/// <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, представляющий мой GridInputPropertyEditor, который является шаблоном, описывающим презентацию для редактирования свойств Grid. Это будет отличаться для графика:
<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>
Используя Snoop, я смог выяснить, что если я установлю Z-Index элемента ListBox на большое число, мой редактор свойств выйдет на первый план. Если кто-то видит лучший способ обойти это, дайте мне знать. В противном случае я мог бы использовать некоторую помощь в создании триггера для повышения и понижения zindex в зависимости от выбранного элемента.