我有一个
ListView
,我尝试用它来模拟 Windows 资源管理器的“列表”视图。为了显示项目,我使用 S. Baeumlisberger 的 VirtualizingWrapPanel
,它可以水平滚动并很好地虚拟化其项目。
但是,在某些时候,用户会希望对项目进行分组(例如按文件类型)。这就是事情变得棘手的地方。分组时,
ListView
使用 <GroupStyle.Panel>
显示多个 VirtualizingWrapPanel
,每组项目一个。
对于这个
<GroupStyle.Panel>
,我使用VirtualizingStackPanel
,并将其Orientation
设置为Horizontal
,因为我希望组水平显示,就像在Windows资源管理器中一样。这可行,但它不会虚拟化它的项目(而当我将其设置为 Vertical
时它会虚拟化)。
这是我的 XAML:
<ListView x:Name="PART_ListView" SelectionMode="Extended"
FocusVisualStyle="{x:Null}" ScrollViewer.IsDeferredScrollingEnabled="False"
ScrollViewer.CanContentScroll="True" BorderThickness="0"
Grid.IsSharedSizeScope="True" VirtualizingPanel.ScrollUnit="Pixel"
VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.CacheLength="2"
VirtualizingPanel.CacheLengthUnit="Page">
<ListView.Resources>
<GroupStyle x:Key="groupStyle">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Margin="0,0,20,0" IsExpanded="True" Style="{DynamicResource lailaShell_GroupByExpanderStyle}">
<Expander.Resources>
<converters:ListViewGroupingHeightConverter x:Key="listViewGroupingHeightConverter" />
</Expander.Resources>
<Expander.Header>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" x:Name="expanderHeader">
<TextBlock Text="{Binding Name}" Foreground="DarkBlue" VerticalAlignment="Center" />
</StackPanel>
</Expander.Header>
<ItemsPresenter Margin="5,0,0,0">
<ItemsPresenter.Height>
<MultiBinding Converter="{StaticResource listViewGroupingHeightConverter}">
<Binding Path="." ElementName="expanderHeader" />
<Binding Path="ActualHeight" ElementName="PART_ListView" />
</MultiBinding>
</ItemsPresenter.Height>
</ItemsPresenter>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.Resources>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<vwp:VirtualizingWrapPanel SpacingMode="None">
<vwp:VirtualizingWrapPanel.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.GroupDescriptions.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}" Value="0">
<Setter Property="vwp:VirtualizingWrapPanel.Margin" Value="20,0,0,0" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Items.GroupDescriptions.Count, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}" Value="1">
<Setter Property="vwp:VirtualizingWrapPanel.Margin" Value="0,0,0,0" />
</DataTrigger>
</Style.Triggers>
</Style>
</vwp:VirtualizingWrapPanel.Style>
</vwp:VirtualizingWrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<i:Interaction.Behaviors>
<behaviors:SelectionBehavior />
</i:Interaction.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<Border>
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="16" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="16" />
<ColumnDefinition Width="4" />
<ColumnDefinition Width="Auto" SharedSizeGroup="A" />
</Grid.ColumnDefinitions>
<Image Source="{Binding PropertiesByKeyAsText[e77e90df-6271-4f5b-834f-2dd1f245dda4:2].FirstIcon16Async, IsAsync=True}"
Width="14" Height="16">
<Image.Style>
<Style>
<Setter Property="Image.Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding PropertiesByKeyAsText[e77e90df-6271-4f5b-834f-2dd1f245dda4:2].HasIcon}" Value="True">
<Setter Property="Image.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Image Grid.Column="2" Source="{Binding IconAsync[16], IsAsync=True}" Width="16" Height="16"
UseLayoutRounding="True" SnapsToDevicePixels="True">
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsHidden}" Value="True">
<Setter Property="Image.Opacity" Value="0.5" />
</DataTrigger>
<DataTrigger Binding="{Binding IsCut}" Value="True">
<Setter Property="Image.Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Image Grid.Column="2" Source="{Binding OverlayImageAsync, IsAsync=True}" Width="16" Height="16"
UseLayoutRounding="True" SnapsToDevicePixels="True"
VerticalAlignment="Bottom" HorizontalAlignment="Left">
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsHidden}" Value="True">
<Setter Property="Image.Opacity" Value="0.5" />
</DataTrigger>
<DataTrigger Binding="{Binding IsCut}" Value="True">
<Setter Property="Image.Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Grid.Column="4" MaxWidth="200"
Text="{Binding DisplayName}" TextTrimming="CharacterEllipsis">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsCompressed}" Value="True">
<Setter Property="TextBlock.Foreground" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
如果您感兴趣,可以在 https://sourceforge.net/p/laila-shell/code/ci/master/tree/ 找到完整的源代码。
我终于成功了!现在是凌晨 2 点 44 分,我们还要再忙两周 :-P
我不知道为什么,但我开始遇到麻烦,
VirtualizingWrapPanel
不断闪烁,直到它变得无法使用,当我破坏程序时,我在堆栈跟踪中看到它不断测量和排列。所以我认为它很难坚持恒定的项目大小,因此我将 ItemSize
的 VirtualizingWrapPanel
属性设置为恒定值。现在突然间我所有的问题都消失了,一切都正常了:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<vwp:VirtualizingWrapPanel SpacingMode="None" Orientation="Vertical" ItemSize="240,20">
</vwp:VirtualizingWrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>