ListView父子菜单仅显示父项,如何实现父子项全部展示?
问题分析与解决方法
核心问题
你的代码存在两个关键问题:
- TemplateSelector逻辑完全颠倒:将有子项的父项判定为子项、使用
ChildTemplate,无子项的子项反而使用ParentTemplate,导致模板匹配错误。 - 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
相关产品推荐
相关产品推荐

