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

ListView父子菜单仅显示父项,如何实现父子项全部展示?

问题分析与解决方法

核心问题

你的代码存在两个关键问题:

  1. TemplateSelector逻辑完全颠倒:将有子项的父项判定为子项、使用ChildTemplate,无子项的子项反而使用ParentTemplate,导致模板匹配错误。
  2. ListView未处理子项展示:仅将父项集合绑定到ListView的ItemsSource,子项作为父项的Children属性,ListView不会自动遍历渲染嵌套子项,需显式在父项模板中添加控件展示子项。

解决方案:嵌套ListView实现层级菜单

这种方式符合父子菜单的层级展示逻辑,父项区域内会直接显示对应的子项(如需折叠/展开可额外添加交互逻辑)。

1. 修正TemplateSelector逻辑

反转判定条件,让有子项的父项使用父模板,无子项的子项使用子模板:

public class MenuItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate ParentTemplate { get; set; }
    public DataTemplate ChildTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        if (item is MenuItem menuItem)
        {
            // 有子项的是父项,使用父模板;无子项的是子项,使用子模板
            return menuItem.Children.Count > 0 ? ParentTemplate : ChildTemplate;
        }
        return base.SelectTemplateCore(item, container);
    }
}

2. 修改父项DataTemplate,嵌入子ListView

在父项模板中添加一个ListView,绑定父项的Children集合,用于展示子项:

<Page.Resources>
    <DataTemplate x:Key="ParentDataTemplate">
        <StackPanel>
            <!-- 父项文本 -->
            <TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="14"/>
            <!-- 子项列表,绑定父项的Children集合 -->
            <muxc:ListView ItemsSource="{Binding Children}" 
                           ItemTemplate="{StaticResource ChildDataTemplate}"
                           BorderThickness="0">
                <muxc:ListView.ItemContainerStyle>
                    <Style TargetType="muxc:ListViewItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                        <Setter Property="Padding" Value="0"/>
                    </Style>
                </muxc:ListView.ItemContainerStyle>
            </muxc:ListView>
        </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="ChildDataTemplate">
        <TextBlock Text="{Binding Name}" Margin="20,0,0,0"/>
    </DataTemplate>

    <local:MenuItemTemplateSelector x:Key="MenuItemTemplateSelector"
                                    ParentTemplate="{StaticResource ParentDataTemplate}"
                                    ChildTemplate="{StaticResource ChildDataTemplate}"/>
</Page.Resources>
<Grid>
    <muxc:ListView x:Name="nestedListView" ItemTemplateSelector="{StaticResource MenuItemTemplateSelector}">
        <muxc:ListView.ItemContainerStyle>
            <Style TargetType="muxc:ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            </Style>
        </muxc:ListView.ItemContainerStyle>

        <muxc:ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsWrapGrid Orientation="Vertical" MaximumRowsOrColumns="2"/>
            </ItemsPanelTemplate>
        </muxc:ListView.ItemsPanel>
    </muxc:ListView>
</Grid>

3. 保持数据逻辑不变

你的数据初始化代码无需修改,父项的Children集合已正确绑定到子ListView的ItemsSource,运行后即可看到父项及对应的子项。

可选方案:扁平化数据集合

如果不需要层级嵌套,希望父项和子项在同一个ListView中平铺展示,可将所有父项和子项合并为扁平集合后绑定:

public MainPage()
{
    this.InitializeComponent();
    MenuItem parentItem = new MenuItem { Name = "Parent Item 1" };
    MenuItem childItem1 = new MenuItem { Name = "Child Item 1" };
    MenuItem childItem2 = new MenuItem { Name = "Child Item 2" };
    parentItem.Children.Add(childItem1);
    parentItem.Children.Add(childItem2);

    MenuItemViewModel viewModel = new MenuItemViewModel();
    // 将父项和所有子项添加到扁平集合
    viewModel.MenuItems.Add(parentItem);
    viewModel.MenuItems.AddRange(parentItem.Children);

    nestedListView.ItemsSource = viewModel.MenuItems;
}

此方式下,修正后的TemplateSelector会自动为父项和子项应用对应模板,实现不同样式的平铺展示。

内容的提问来源于stack exchange,提问作者Su Myat Kyaw

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:04:54