ItemsControl中使用的WPF扩展器覆盖

本文关键字:WPF 扩展器 覆盖 ItemsControl | 更新日期: 2023-09-27 18:26:51

我已经搜索了一段时间,但我找到的所有解决方案都只解决了部分问题。我想要一个ItemsControl,每个项目都包含一个扩展器。展开时,扩展器的内容应显示为覆盖ItemsControl中的其他项,而不是向下移动它们。

下面的XAML代码正好解决了一个大问题:扩展器的内容不与其他项重叠,而是隐藏在它们后面。我想这是由于ZIndex,因为ItemsControl中的以下项目被添加到扩展器的内容之后。

我设法使用样式触发器将一个Expander的ZIndex设置为99,但这似乎是一个过于复杂且容易出错的解决方案。有什么想法吗?

<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350"
        Width="525">
  <Window.Resources>
    <x:Array x:Key="items"
             Type="sys:String" 
             xmlns:sys="clr-namespace:System;assembly=mscorlib">
      <sys:String>One</sys:String>
      <sys:String>Two</sys:String>
      <sys:String>Three</sys:String>
      <sys:String>Four</sys:String>
    </x:Array>
    <DataTemplate x:Key="template">
      <Grid Background="Red" Margin="0,0,0,10">
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding}" />
        <Canvas Height="25" Grid.Row="1">
          <Expander ExpandDirection="Down" Header="Header" Grid.Row="1">
            <Expander.Content>
              <TextBlock Height="80" Text="Content" Background="Yellow" />
            </Expander.Content>
          </Expander>
        </Canvas>
      </Grid>
    </DataTemplate>
  </Window.Resources>
  <Grid>
    <ScrollViewer>
      <ItemsControl ItemsSource="{StaticResource items}"
                    ItemTemplate="{StaticResource template}"
                    HorizontalContentAlignment="Stretch">
      </ItemsControl>
    </ScrollViewer>
  </Grid>
</Window>

ItemsControl中使用的WPF扩展器覆盖

用你尝试的方式实现这一点会很困难。问题是嵌套结构——因为每个Canvas都嵌套在一个Grid内,所以你将无法控制它相对于其他Canvas元素的z索引。为了说明这一点,下面是由当前标记创建的视觉树的示意图:

<StackPanel>              <!-- items panel -->
    <ContentPresenter>    <!-- item wrapper -->
        <Grid>
            <Canvas>
            </Canvas>
        </Grid>
    </ContentPresenter>
    <ContentPresenter>    <!-- item wrapper -->
        <Grid>
            <Canvas>
            </Canvas>
        </Grid>
    </ContentPresenter>
</StackPanel>

参考以上内容,您的目标是使Canvas元素出现在其父ContentPresenter的同级元素前面。这在该层次结构中是不可能的,因为ZIndex仅相对于同一父元素的同级元素应用。现在,可能有一些方法可以将以上内容按摩成一个平面结构,这样您就可以根据需要应用ZIndex扩展内容。

然而,我认为一种更简单、更自然的方法是将Popup元素用于扩展的内容。Popup是一个位于视觉树之外的框架基元,它将始终位于其他内容之上。您可以使用ToggleButton或类似的东西来创建"展开"效果。例如:

<StackPanel Grid.Row="1">
    <ToggleButton x:Name="PopupToggle" Content="Expand" />
    <Popup IsOpen="{Binding IsChecked,ElementName=PopupToggle}">
        <TextBlock Height="80" Text="Content" Background="Yellow" />
    </Popup>
</StackPanel>