1、递归
下面是Winform的递归添加菜单栏数据,数据设置好父子id方便递归使用
在TreeView的控件窗口加载时,调用递归加载菜单
private void LoadTvMenu()
{
this.nodeList = objService.GetAllMenu(); // 通过Service得到全部数据
// 创建一个根节点
this.tv_MenuList.Nodes.Clear(); // 亲空所有节点
// 这个是TreeView的节点
TreeNode rootNode = new TreeNode();
rootNode.Text = "学员管理系统";
rootNode.Tag = "0"; // 暂时没什么用
rootNode.ImageIndex = 0; // 设置根节点现实的图片
this.tv_MenuList.Nodes.Add(rootNode); // 将根节点添加到treeview根节点
// 基于递归方式添加所有子节点
CreateChildNode(rootNode, "0");
}
private void CreateChildNode(TreeNode parentNode, string preId)
{
var nodes = from list in nodeList
where list.ParentId.Equals(preId)
select list;
foreach (var item in nodes)
{
TreeNode node = new TreeNode();
node.Text = item.MenuName;
node.Tag = item.MenuCode;
// 设置节点图表
if (item.ParentId == "0")
{
node.ImageIndex = 1;
}
else
{
node.ImageIndex = 3;
}
parentNode.Nodes.Add(node); // 给父节点添加上这个子节点
// 递归调用
CreateChildNode(node, item.MenuId.ToString());
this.tv_MenuList.Nodes[0].Expand(); // 将一级目录全部展开
this.tv_MenuList.ExpandAll();
}
}
在WPF中也是差不多的可以用递归实现加载TreeView
2、WPF中可以使用HierarchicalDataTemplate非常方便
创建数据类
public class ListLeagueList : ObservableCollection<League>
{
List<League> leagues = new List<League>();
List<Division> divisions = new List<Division>();
List<Team> teams = new List<Team>();
public ListLeagueList()
{
teams.Add(new Team() { Name = "Team 1" });
teams.Add(new Team() { Name = "Team 2" });
teams.Add(new Team() { Name = "Team 3" });
teams.Add(new Team() { Name = "Team 4" });
divisions.Add(new Division() { Name = "Division 1", Teams = teams });
divisions.Add(new Division() { Name = "Division 2", Teams = teams });
divisions.Add(new Division() { Name = "Division 3", Teams = teams });
Add(new League() { Name = "League a", Divisions = divisions });
Add(new League() { Name = "League b", Divisions = divisions });
Add(new League() { Name = "League c", Divisions = divisions });
}
}
view中 设置下一个子集合为ItemsSource
<DockPanel>
<DockPanel.Resources>
<local:ListLeagueList x:Key="myList" />
<HierarchicalDataTemplate DataType="{x:Type models:League}" ItemsSource="{Binding Divisions}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type models:Division}" ItemsSource="{Binding Teams}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<!-- 最后一个没有ItemsSource -->
<HierarchicalDataTemplate DataType="{x:Type models:Team}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
</DockPanel.Resources>
<Menu
x:Name="menu1"
Margin="10"
DockPanel.Dock="Top">
<MenuItem Header="我的足球联赛" ItemsSource="{Binding Source={StaticResource myList}}" />
</Menu>
<TreeView x:Name="treeView1">
<TreeViewItem Header="我的足球联赛" ItemsSource="{Binding Source={StaticResource myList}}" />
</TreeView>
</DockPanel>
使用HierarchDataTemplate后可以显示多层的控件都可以使用
-- 这里的ItemsSource是集合,使用其它方式绑定上也是一样的;HierarchicalDataTemplate就是独立于这个集合的,检测到合适就起作用
HierarchicalDataTemplate使用样例2(实现菜单栏):
WPF中:
<TreeView
Margin="0,10"
Background="Transparent"
BorderThickness="0"
ItemsSource="{Binding Menus}"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<TreeView.ItemTemplate>
<!-- TreeView也有模板,上面是TreeViewItem的模板 -->
<HierarchicalDataTemplate ItemsSource="{Binding Children}"> <!--这里比较伟大的地方就是绑定的是子类-->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Name="c1" Width="30" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- 左侧图标 -->
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{StaticResource Iconfont}"
FontSize="18"
SnapsToDevicePixels="True"
Text="{Binding MenuIcon}" />
<!-- 右侧文字 -->
<TextBlock
Grid.Column="1"
Margin="5,0,0,0"
FontSize="13"
Text="{Binding MenuHeader}" />
</Grid>
<!--没有就图标都不要显示了-->
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding MenuIcon}" Value="{x:Null}">
<Setter TargetName="c1" Property="Width" Value="0" />
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
这个页面的ViewModel,通过递归加载菜单
public class TreeMenuViewModel
{
public List<MenuItemModel> Menus { get; set; } = new List<MenuItemModel>();
// 列表,没有树形结构
private List<MenuEntity> origMenMenus = null;
private readonly IRegionManager _regionManager;
public TreeMenuViewModel(IRegionManager regionManager)
{
this._regionManager = regionManager; // 要在FillMenus调用前赋值要不然就是null
// 需要获取菜单数据
origMenMenus = GlobalEntity.CurrentUserInfo?.Menus; // 这个用户的菜单
this.FillMenus(Menus, 0);
}
/// <summary>
/// 递归遍历出所有的菜单
/// </summary>
/// <param name="menus"></param>
/// <param name="parentId"></param>
private void FillMenus(List<MenuItemModel> menus, int parentId)
{
var sub = origMenMenus.Where(m => m.ParentId == parentId).OrderBy(m => m.Index);
if (sub.Count() > 0)
{
foreach (var item in sub)
{
MenuItemModel mm = new MenuItemModel(_regionManager)
{
MenuHeader = item.MenuHeader,
MenuIcon = item.MenuIcon,
TargetView = item.TargetView,
};
menus.Add(mm);
// 自己调用自己
FillMenus(mm.Children = new List<MenuItemModel>(), item.MenuId);
}
}
}
}
Item实体:
public class MenuItemModel : BindableBase
{
public string MenuIcon { get; set; }
public string MenuHeader { get; set; }
public string TargetView { get; set; }
private bool _isExpanded;
public bool IsExpanded
{
get { return _isExpanded; }
set { SetProperty(ref _isExpanded, value); }
}
public List<MenuItemModel> Children { get; set; }
// 这个打开是将用户控件注入到MainContentRegion,显示出来
public ICommand OpenViewCommand
{
get => new DelegateCommand(() =>
{
if (_regionManager == null)
{
}
else
{
}
if ((this.Children == null || this.Children.Count == 0) &&
!string.IsNullOrEmpty(this.TargetView))
{
// 页面跳转(目前只实现了UserManagementView窗口)
_regionManager.RequestNavigate("MainContentRegion", this.TargetView); // 更换区域导航
}
else
this.IsExpanded = !this.IsExpanded; // 点了就更换状态
});
}
IRegionManager _regionManager = null;
// 构造方法注入区域管理
public MenuItemModel(IRegionManager regionManager)
{
_regionManager = regionManager;
}
}