You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现带「显示更多X项」功能的ListBox样式控件

实现可展开/收起的ListBox控件(显示隐藏条目数)

我想做一个能通过Expander切换展开/收起状态的列表控件:收起时固定显示3项,同时提示隐藏的条目数量;点击后展开查看全部,再次点击回到仅显示3项的状态。自己写了个样式,但效果差、外观不佳,希望得到改进方案或更规范的实现方式。

原实现代码

XAML样式

<Style x:Key="CustomListBoxKey" TargetType="{x:Type ListBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <ItemsPresenter/>
                    <Expander x:Name="Expander" Grid.Row="1" Header="Show X More" ExpandDirection="Down"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding ElementName=Expander, Path=IsExpanded}" Value="False">
                        <Setter Property="MaxHeight" Value="80"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding ElementName=Expander, Path=IsExpanded}" Value="True">
                        <Setter Property="MaxHeight" Value="Infinity"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

绑定数据源(C#)

public List<string> Items { get; set; } = new() { "A", "B", "C", "D", "E", "F", "G", "H", "I" };

使用示例

<Grid>
    <ListBox ItemsSource="{Binding Items}" Style="{StaticResource CustomListBoxKey}" VerticalAlignment="Top">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=.}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

改进后的规范实现方案

核心优化点

  • 动态计算并显示隐藏条目数,替换固定文本
  • 基于Item高度计算收起时的MaxHeight,避免硬编码数值
  • 优化布局结构,让Expander与ListBox的交互更自然
  • 自动隐藏条目数≤3时的Expander
  • 展开时启用滚动条,避免内容溢出

完整代码实现

XAML样式与转换器引用

<Window.Resources>
    <!-- 可折叠ListBox样式 -->
    <Style x:Key="CollapsibleListBoxStyle" TargetType="{x:Type ListBox}">
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBox}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <!-- 包裹ItemsPresenter,控制收起高度 -->
                        <ScrollViewer x:Name="ItemsScrollViewer" 
                                      Grid.Row="0"
                                      VerticalScrollBarVisibility="Hidden"
                                      HorizontalScrollBarVisibility="Disabled">
                            <ItemsPresenter/>
                        </ScrollViewer>
                        <!-- 动态显示状态的Expander -->
                        <Expander x:Name="ItemsExpander"
                                  Grid.Row="1"
                                  Margin="0,4,0,0"
                                  HorizontalAlignment="Stretch"
                                  ExpandDirection="Down">
                            <Expander.Header>
                                <TextBlock>
                                    <Run Text="{Binding ElementName=ItemsScrollViewer, Path=ExtentHeight, Converter={StaticResource HiddenItemsCountConverter}, ConverterParameter={Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemHeight}}"/>
                                    <Run Text=" 项"/>
                                </TextBlock>
                            </Expander.Header>
                        </Expander>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <!-- 条目数≤3时隐藏Expander -->
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items.Count}" Value="0">
                            <Setter TargetName="ItemsExpander" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items.Count}" Value="1">
                            <Setter TargetName="ItemsExpander" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items.Count}" Value="2">
                            <Setter TargetName="ItemsExpander" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items.Count}" Value="3">
                            <Setter TargetName="ItemsExpander" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                        <!-- 收起状态:限制高度为3个Item的总高度 -->
                        <DataTrigger Binding="{Binding ElementName=ItemsExpander, Path=IsExpanded}" Value="False">
                            <Setter TargetName="ItemsScrollViewer" Property="MaxHeight" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemHeight, Converter={StaticResource MultiplyConverter}, ConverterParameter=3}"/>
                            <Setter TargetName="ItemsExpander" Property="Header" Value="{Binding ElementName=ItemsScrollViewer, Path=ExtentHeight, Converter={StaticResource HiddenItemsCountConverter}, ConverterParameter={Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemHeight}} 项"/>
                        </DataTrigger>
                        <!-- 展开状态:取消高度限制,显示滚动条 -->
                        <DataTrigger Binding="{Binding ElementName=ItemsExpander, Path=IsExpanded}" Value="True">
                            <Setter TargetName="ItemsScrollViewer" Property="MaxHeight" Value="Infinity"/>
                            <Setter TargetName="ItemsScrollViewer" Property="VerticalScrollBarVisibility" Value="Auto"/>
                            <Setter TargetName="ItemsExpander" Property="Header" Value="收起"/>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 计算隐藏条目数的转换器 -->
    <local:HiddenItemsCountConverter x:Key="HiddenItemsCountConverter"/>
    <!-- 乘法转换器,计算3个Item的总高度 -->
    <local:MultiplyConverter x:Key="MultiplyConverter"/>
</Window.Resources>

转换器代码(C#)

public class HiddenItemsCountConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double extentHeight && parameter is double itemHeight && itemHeight > 0)
        {
            var totalItems = Math.Floor(extentHeight / itemHeight);
            var visibleItems = 3;
            return totalItems > visibleItems ? totalItems - visibleItems : 0;
        }
        return 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class MultiplyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double itemHeight && double.TryParse(parameter.ToString(), out double multiplier))
        {
            return itemHeight * multiplier;
        }
        return 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

使用示例

<Grid>
    <ListBox ItemsSource="{Binding Items}" 
             Style="{StaticResource CollapsibleListBoxStyle}"
             ItemHeight="24" <!-- 固定Item高度,确保计算准确 -->
             VerticalAlignment="Top">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" Padding="4,2"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

关键说明

  1. 动态文本:通过转换器自动计算隐藏条目数,Expander标题会根据状态切换为"X项"或"收起"
  2. 自适应高度:收起时的MaxHeight由ItemHeight乘以3得到,确保刚好显示3项,适配不同Item高度
  3. 智能隐藏:当列表条目数≤3时,Expander自动隐藏,避免冗余控件
  4. 滚动支持:展开时启用垂直滚动条,避免内容超出容器范围

内容的提问来源于stack exchange,提问作者Easdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 04:05:15