問題描述
如何使用 Windows 資源管理器顯示項目和詳細信息展開/折疊 (How to Display Items and Details with Windows Explorer Expand/Collapse)
I have some items that I want to show to the user in a WPF window, but I want to hide the details of each item until the user selects/expands the item. I'd like to achieve Windows‑Explorer‑esque functionality, where the item Header is always displayed, and the item Details (as an ItemsControl
) are displayed when the user clicks on the item's arrow.
Is there an obvious way to do this? Or am I going to have to whip out a custom control?
參考解法
方法 1:
This can be done with the standard WPF Treeview. Josh Smith's article on Simplifying the WPF TreeView includes a sample showing how to provide lazy‑loading of the data for the subitems within each TreeViewItem
.
The basic approach is to make a "dummy" child of each item in the ViewModel
, and track the expanded state of each TreeViewItem
. As a TreeViewItem
is expanded, the dummy child is removed and replaced with the real data.
方法 2:
If you are just looking to automatically expand/collapse items then you probably want a trigger. For example you can use an expander and automatically Expand it when the mouse is over it.
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsExpanded" Value="True"/>
</Trigger>
</ControlTemplate.Triggers>
And of course this can be repeated for other triggers that you want to set it to be open
<Expander Header="Hello" IsExpanded="False">
<Border Background="Red" Height="32"/>
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<StackPanel>
<ContentPresenter Content="{TemplateBinding Header}"/>
<ContentPresenter x:Name="expander" Content="{TemplateBinding Content}" Visibility="Collapsed"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="expander" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Expander.Style>
</Expander>
If you don't need a full tree like UI then it would probably be sufficient to just have a list of these, but I'm pretty sure you can also use the same trick on a treeviewitem too.
方法 3:
I took the ListBox
of Expander
s path, and I am pretty pleased with the results.
Here's how my final code ended up:
Control Template for Expander Button
<ControlTemplate x:Key="TreeViewToggleButton" TargetType="{x:Type ToggleButton}">
<Border x:Name="ToggleButtonBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<Grid>
<Rectangle Fill="Transparent"/>
<Path x:Name="Arrow"
Height="10" Width="10"
Stroke="Black"
Data="m 2 1 v 8 l 4 ‑3.75 Z">
</Path>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Arrow" Property="Data" Value="m 2 9 h 5 v ‑5 Z"/>
<Setter TargetName="Arrow" Property="Fill" Value="Black"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Arrow" Property="Stroke" Value="#00A7C2"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="Arrow" Property="Fill" Value="#00A7C2"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Control Template for Expander
<ControlTemplate x:Key="TreeViewExpander" TargetType="{x:Type Expander}">
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ToggleButton x:Name="ExpanderButton"
Grid.Column="0"
Template="{StaticResource TreeViewToggleButton}"
IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True"
Padding="2, 0" />
<Label Grid.Column="1" Content="{TemplateBinding Header}"
Padding="0, 1"/>
</Grid>
<ContentPresenter x:Name="ExpanderContent"
Visibility="Collapsed"
DockPanel.Dock="Bottom"/>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ExpanderContent" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Usage in Window
<ListBox Grid.Row="1" DataContext="{Binding Inputs}" ItemsSource="{Binding}" ScrollViewer.CanContentScroll="False">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Expander Template="{StaticResource TreeViewExpander}"
IsExpanded="{Binding IsExpanded}">
<Expander.Header>
<TextBlock Text="{Binding Timestamp, StringFormat=Time: {0}}"/>
</Expander.Header>
<ItemsControl ItemsSource="{Binding Variables}" Margin="30 0 0 0"/>
</Expander>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
(by Joseph、Reed Copsey、AlSki、Joseph)