利用Prism 搭建的一个WPF MVVM框架,导入了Material Design UI库,在实现TreeView时费了点周折,记录于此。
Xaml的写法如下:
需要应用命名空间:
xmlns:domain="clr-namespace:management.wpfUI.Models" xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TreeView x:Name="treeView" Grid.Row="0" Foreground="White" ItemsSource="{Binding NavMenus}" MinWidth="220"> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type domain:NavMenuModel}" ItemsSource="{Binding ChildMenus}"> <TextBlock Text="{Binding MenuName}" Margin="3 2" /> </HierarchicalDataTemplate> <DataTemplate DataType="{x:Type domain:MenuModel}"> <TextBlock Text="{Binding MenuName}" Margin="3 2" /> </DataTemplate> </TreeView.Resources> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectedItemChanged"> <i:InvokeCommandAction Command="{Binding SelectItemChangeCommand}" CommandParameter="{Binding ElementName=treeView,Path=SelectedItem}"/> </i:EventTrigger> </i:Interaction.Triggers> </TreeView>绑定的数据源对象定义如下:
public class NavMenuModel:MenuModel { public NavMenuModel() { ChildMenus = new ObservableCollection<MenuModel>(); } public ObservableCollection<MenuModel> ChildMenus { get; } } public class MenuModel { public int Id { get; set; } public int ParentId { get; set; } public string MenuName { get; set; } public MenuModel() { } public MenuModel(int menuId,string menuName, int parentMenuId, params MenuModel[] subItems) { this.Id = menuId; this.MenuName = menuName; this.ParentId = parentMenuId; } }ViewModel写法:
public class LeftMenuViewModel: BindableBase { public ObservableCollection<NavMenuModel> NavMenus { get; } public ICommand SelectItemChangeCommand { get { return new BaseCommand<object>((param) => { if (param != null) { SelectedItem = param as MenuModel; } }); } } public LeftMenuViewModel() { NavMenus = new ObservableCollection<NavMenuModel>(); var menu = new NavMenuModel() { Id = 1, MenuName = "Chapter 1" }; var subMenu = new NavMenuModel() { Id = 11, MenuName = "Chapter 1.1", ParentId = 1 }; subMenu.ChildMenus.Add(new MenuModel() { Id=111, MenuName="Chapter 1.1.1", ParentId= 11 }); menu.ChildMenus.Add(subMenu); NavMenus.Add(menu); var m2 = new NavMenuModel() { Id = 2, MenuName = "Chapter 2" }; var subMenu2 = new NavMenuModel() { Id = 21, MenuName = "Chapter 2.1", ParentId =1 }; m2.ChildMenus.Add(subMenu2); NavMenus.Add(m2); NavMenus.Add(new NavMenuModel() { Id = 3, MenuName = "Chapter 3" }); } private MenuModel _selectedItem; public MenuModel SelectedItem { get { return _selectedItem; } set { SetProperty(ref _selectedItem, value); } } }实现的效果如下:
开发过程中需要注意1:DataType="{x:Type domain:MenuModel}" 不能为同一个对象,利用继承来规避此问题,否则报错:
注意2:HierarchicalDataTemplate 的ItemSource 绑定层级关系和 TreeView挂载的ItemSource不同;
注意3:SelectItem引用父类型对象,避免null发生;