WrapPanel 中的 ListViewItem 在折叠时占用 space

ListViewItem in WrapPanel occupying space when collapsed

我有一个ListView使用WrapPanel作为它的ItemsPanel,我直接使用ListViewItem作为内容。但是当一个 ListViewItem.VisibilityCollapsed 时,你仍然可以看到它正在使用的 space。

首先,示例 XAML 代码类似于我使用的代码:

<Grid>
    <ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" ItemContainerStyle="{DynamicResource ContainerStyle}">
        <ListView.Resources>
            <Style TargetType="{x:Type ListViewItem}" x:Key="ContainerStyle">
                <Setter Property="Background" Value="Transparent" />
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListViewItem}">
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListView.Resources>
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel ItemHeight="200" ItemWidth="200"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListViewItem Margin="10" Visibility="Visible">
            <Border Background="Red"/>
        </ListViewItem>
        <ListViewItem Margin="10" Visibility="Visible">
            <Border Background="Blue"/>
        </ListViewItem>
        <ListViewItem Margin="10" Visibility="Visible">
            <Border Background="Green"/>
        </ListViewItem>
    </ListView>
</Grid>

例如,当所有项目都可见时(上面的代码)我有这个:

但是如果我更改第一项使其折叠如下

<ListViewItem Margin="10" Visibility="Collapsed">
    <Border Background="Red"/>
</ListViewItem>

结果是这样的:

我期望的是以下内容:

因此我不明白为什么它会这样,Collapsed 似乎表现得像 Hidden。我直接将它应用到项目上,看不出还能做什么。

我尝试了不同的解决方案,最值得注意的是 this one about binding to Visibility in the style and 但没有成功,结果相同。

我认为您看到的问题与即使折叠,ListViewItem 仍然是 Item,WrapPanel 将检测到 3 个项目,而不是 2 个有关。

一个很好的工作解决方案似乎是在自定义面板中覆盖面板的 "Arrange" 方法。

我正在这个伟大的 class AlignableWrapPanel 的基础上工作(继承自 Panel,而不是 WrapPanel),我通过替换它来让它工作:

var child = children[i];
if (child == null) continue;

有了这个 :

var child = children[i];
if (child == null) continue;
if (child.Visibility == Visibility.Collapsed) continue;

方法有ArrangeOverrideArrangeLineMeasureOverrideArrangeLine 有点不同,但是带有 if(child == null) continue; 的那一行很容易识别;只需在之后添加带有 Collapsed 的那个即可。

该解决方案适用于任何

接受的答案实际上没有提供解决方案,而是在其评论部分提供。

如果您设置 ItemWidth,WrapPanel 将为所有绑定到自身的项目保留 ItemWidth,无论是否可见。

这里的解决方法是不在 WrapPanel 上设置 ItemWidth,而是在 ItemTemplate 上设置 Width。

<ItemsControl.ItemsPanel>
   <ItemsPanelTemplate>
       <WrapPanel />
   </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

<ItemsControl.ItemTemplate>
   <DataTemplate>
       <StackPanel MinWidth="96" />
   </DataTemaplate>
</ItemsControl.ItemTemplate>