利用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发生;