WPF 保姆级教程怎么实现一个树形菜单
先看一下效果吧:
我们直接通过改造一下原版的TreeView来实现上面这个效果
我们先创建一个普通的TreeView
代码很简单:
<TreeView>
<TreeViewItem Header="人事部"/>
<TreeViewItem Header="技术部">
<TreeViewItem Header="技术部-1"/>
<TreeViewItem Header="技术部-1"/>
</TreeViewItem>
<TreeViewItem Header="财务部"/>
</TreeView>
实现的效果如下:
如果把这个当成是项目的菜单栏,应该会被领导骂死,一个是不够灵活,数据是写死的;二是样式不好看,只有点文字部分才会展开。
创建一下模板
直接在设计器中右键我们的item,编辑副本,点击确定,我们会得到下面一段代码
里面有一个叫Bd的border,我们把这个border的背景色去掉,然后我们自己去创建两个新的border
<Border Background="Transparent" Margin="-200,0,-200,0" Grid.ColumnSpan="4"/>
<Border x:Name="bd1" Background="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"
Margin="-200,0,-200,0" Visibility="Hidden" Grid.ColumnSpan="4">
<Border.Effect>
<DropShadowEffect BlurRadius="5" ShadowDepth="2"/>
</Border.Effect>
</Border>
<ToggleButton x:Name="Expander" ClickMode="Press"
IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
上面红色部分是我们新增的两个border,原本的叫Bd的border,我们只保留紫色部分的属性.
原本的代码里面有两个关于Bd的trigger
我们取名为bd1的border,最开始的Visibility设置的是Hidden,我们替换一下关于Bd的trigger,让它变成当IsSelected是true的情况下,让bd1的Visibility变成Visible.
<Trigger Property="IsSelected" Value="true">
<Setter Property="Visibility" TargetName="bd1" Value="Visible"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Visibility" TargetName="bd1" Value="Visible"/>
<Setter Property="Background" TargetName="bd1" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
再运行一下,看一下效果
基本上已经算是成功一半了,但是这个时候,我们的菜单只有一个有效果,其他的还是原来的样式,那是因为我们只有一个TreeViewItem使用了我们写的效果
如果我们每一个TreeViewItem都复制一下这句Style="{DynamicResource TreeViewItemStyle1}" ,是不是显得很呆,而且这只是在我们的菜单很少的情况下,如果菜单很多,这个方法就不可行。
所以这里我们用一个TreeView的ItemContainerStyle来操作一下
<Style x:Key="treeViewStyle1" TargetType="{x:Type TreeView}" BasedOn="{StaticResource {x:Type TreeView}}">
<Setter Property="ItemContainerStyle" Value="{StaticResource TreeViewItemStyle1}"/>
</Style>
我们创建一个类型是TreeView的style,把它的ItemContainerStyle设置成我们之前添加的那个style,然后我们把这个style放到我们的TreeView上
这个时候我们再运行就会发现首级菜单的样式都实现我们想要的效果了,但是子集菜单还是原来的样式
我们在代码里面添加下面一个方法
private void ApplyItemContainerStyle(ItemsControl itemsControl)
{
foreach (var item in itemsControl.Items)
{
var treeViewItem = item as TreeViewItem;
if (treeViewItem != null)
{
treeViewItem.Style = treeview1.ItemContainerStyle;
ApplyItemContainerStyle(treeViewItem);
}
}
}
然后我们在构造函数里面把我们的TreeView当做是参数传进去
这个方法就是把所有的item和item的子项都设置成treeview的ItemContainerStyle;
我们再启动一下项目,就会发现效果是我们想要的效果了
到这里其实大部分效果都实现了,基本上也可以向领导交差了;
但是还缺少一个数据可拓展性和一个图标的功能,我们先看一下数据可拓展性
在平时的项目里面,一般都会有很多个不同的项目,每个项目可能都有好多个菜单,有的项目还想隐藏某一些菜单,我们总不能所有项目都通过visible属性来设置吧
特别是报表功能可能会有几十个,所以我们需要用到一个东西叫数据模板:HierarchicalDataTemplate;
我们先创建一个类
public class TreeViewModel
{
public string Header { get; set; }
public ObservableCollection<TreeViewModel> Children { get; set; }
}
然后回到设计器里面,把我们的代码改成下面的代码
<TreeView Style="{DynamicResource treeViewStyle1}" x:Name="treeview1">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:TreeViewModel}" ItemsSource="{Binding Children}">
<StackPanel Height="40" Orientation="Horizontal">
<TextBlock Text="{Binding Header}" VerticalAlignment="Center"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
对比一下红色部分的绑定,和类的属性,就能知道这个数据模板怎么用了.
再到构造函数里面去添加数据
public ObservableCollection<TreeViewModel> MenuCollection { get; set; } public MainWindow()
{
InitializeComponent(); MenuCollection = new ObservableCollection<TreeViewModel>()
{
new TreeViewModel
{
Header = "人事部"
},
new TreeViewModel
{
Header = "技术部",
Children = new ObservableCollection<TreeViewModel>
{
new TreeViewModel { Header = "技术部-1"},
new TreeViewModel { Header = "技术部-2"},
}
},
new TreeViewModel
{
Header = "财务部",
},
}; treeview1.ItemsSource = MenuCollection;
}
注意这两段标红的代码,我们用一个集合MenuCollection模拟一下我们从数据库或者其他地方查询出来的菜单集合,然后把它做为数据源给treeview就可以了
再运行一下项目,它就差不多实现我们想要的效果了,现在再去找领导交差,领导还会夸你做的不错,只是还差一个图标了,这个就是锦上添花的东西了.
我们百度搜索一下 阿里ICON,去到官网里面,创建一个自己的账号,然后搜索一些自己喜欢的图标
把自己喜欢的图标添加到自己的项目中去,这里的项目名很重要,我取的是 FatSheep
在到我的项目里面去把这个资源文件下载到自己的项目中
下载下来的文件,我们把ttf后缀的文件添加到我们的项目里面去
把它作为资源引入到代码里面
<FontFamily x:Key="FatSheep">pack:application:,,,/自己项目的名字;component/Resources/iconfont.ttf#FatSheep</FontFamily>
记得修改一下自己的项目名字,我取的是TreeViewDemo,改成自己的项目名就好了,最后的结尾,是FatSheep,记得改成自己的ICON项目名称
接着我们在TreeViewModel里面添加一个Icon属性
public class TreeViewModel
{
public string Header { get; set; }
public string Icon { get; set; }
public ObservableCollection<TreeViewModel> Children { get; set; }
}
然后我们在数据源里面添加一下数据
MenuCollection = new ObservableCollection<TreeViewModel>()
{
new TreeViewModel
{
Header = "人事部",
Icon = "\ue71c"
},
new TreeViewModel
{
Header = "技术部",
Icon = "\ue71c",
Children = new ObservableCollection<TreeViewModel>
{
new TreeViewModel { Header = "技术部-1", Icon="\ue71c"},
new TreeViewModel { Header = "技术部-2" , Icon="\ue71c"},
}
},
new TreeViewModel
{
Header = "财务部",
Icon = "\ue71c"
},
};
设计器里面添加一下显示部分的代码
<TreeView Style="{StaticResource treeViewStyle1}" x:Name="treeView1" BorderThickness="0,0,1,0" Grid.Column="1">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:TreeViewModel}" ItemsSource="{Binding Children}">
<StackPanel Height="40" Orientation="Horizontal">
<TextBlock Text="{Binding Icon}" VerticalAlignment="Center" FontFamily="{StaticResource FatSheep}" Margin="0,0,5,0"/>
<TextBlock Text="{Binding Header}" VerticalAlignment="Center"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
再启动项目,功能就完成了
这个笑脸是怎么来的了
那是因为我自己的项目里面添加了一个笑脸
我们复制一下这个代码, 我们把它改成 \ue71c,这是一个转义字符,就这样我们就能添加如何自己喜欢的图标了。
项目github地址:bearhanQ/WPFFramework: Share some experience (github.com)
QQ技术交流群:332035933;
欢迎进群讨论问题,不论是winform,还是wpf,还是.net core的,还有很多萌妹.
WPF 保姆级教程怎么实现一个树形菜单的更多相关文章
- 保姆级教程——Ubuntu16.04 Server下深度学习环境搭建:安装CUDA8.0,cuDNN6.0,Bazel0.5.4,源码编译安装TensorFlow1.4.0(GPU版)
写在前面 本文叙述了在Ubuntu16.04 Server下安装CUDA8.0,cuDNN6.0以及源码编译安装TensorFlow1.4.0(GPU版)的亲身经历,包括遇到的问题及解决办法,也有一些 ...
- 自建本地服务器,自建Web服务器——保姆级教程!
搭建本地服务器,Web服务器--保姆级教程! 本文首发于https://blog.chens.life/How-to-build-your-own-server.html. 先上图!大致思路就是如此. ...
- Eclipse for C/C++ 开发环境部署保姆级教程
Eclipse for C/C++ 开发环境部署保姆级教程 工欲善其事,必先利其器. 对开发人员来说,顺手的开发工具必定事半功倍.自学编程的小白不知道该选择那个开发工具,Eclipse作为一个功能强大 ...
- 强大博客搭建全过程(1)-hexo博客搭建保姆级教程
1. 前言 本人本来使用国内的开源项目solo搭建了博客,但感觉1核CPU2G内存的服务器,还是稍微有点重,包括服务器内还搭建了数据库.如果自己开发然后搭建,耗费时间又比较多,于是乎开始寻找轻量型的博 ...
- RocketMQ保姆级教程
大家好,我是三友~~ 上周花了一点时间从头到尾.从无到有地搭建了一套RocketMQ的环境,觉得还挺easy的,所以就写篇文章分享给大家. 整篇文章可以大致分为三个部分,第一部分属于一些核心概念和工作 ...
- 上一个树形菜单的改进,增添了数据绑定功能而非仅仅的jq特效
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- 【良心保姆级教程】java手把手教你用swing写一个学生的增删改查模块
很多刚入门的同学,不清楚如何用java.swing去开发出一个系统? 不清楚如何使用java代码去操作数据库进行增删改查一些列操作,不清楚java代码和数据库(mysql.sqlserver)之间怎么 ...
- [保姆级教程] 如何在 Linux Kernel (V5.17.7) 中添加一个系统调用(System call)
最近在学习 <linux Kernel Development>,本书用的linux kernel 是v2.6 版本的.看完"系统调用"一节后,想尝试添加一个系统调用, ...
- 保姆级教程!手把手教你使用Longhorn管理云原生分布式SQL数据库!
作者简介 Jimmy Guerrero,在开发者关系团队和开源社区拥有20多年的经验.他目前领导YugabyteDB的社区和市场团队. 本文来自Rancher Labs Longhorn是Kubern ...
- 保姆级教程,如何发现 GitHub 上的优质项目?
先看再点赞,给自己一点思考的时间,微信搜索[沉默王二]关注这个靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我的系列文章. ...
随机推荐
- java后端解决请求跨域
跨域 跨域:指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制. 例如:a页面想获取b页面资源,如果a.b页面的协议.域名.端口.子域名不同 ...
- Java 知识总结大汇总!看完哪个都变大佬!
免费编程资源大全项目:https://github.com/liyupi/free-programming-resources 大家好,我是鱼皮,今天分享 十几个 让人直呼 "哇塞" ...
- oeasy教您玩转 linux 010212 管道 pipe
上一部分我们都讲了什么? 牛说cowsay 牛可以有各种表情 可以自定义眼睛 可以变成各种别的小动物 可以说也可以想cowthink 我们也想让牛说出字符画的感觉 回顾字符画 下载figlet和toi ...
- 第七节 JMeter基础-高级登录【数据驱动-参数化】
声明:本文所记录的仅本次操作学习到的知识点,其中商城IP错误,请自行更改. 背景:一个接口的不同情况,其实就是请求参数不一样.期望结果不一样.把这些不一样的东西都提取出来进行管理,下次可以直接使用.因 ...
- Centos7下安装配置最新版本Jenkins(2.452.3)
1.基础环境配置 1.1 服务器下载Jenkins安装包 下载地址:https://www.jenkins.io/download/ 下载命令:wget https://get.jenkins.io/ ...
- 关于mybatisplus与mybatis的自动填充混用问题
public class MybatisPlusAutoFillHandler implements MetaObjectHandler { //插入时的填充策略 @Override public v ...
- browsermob-proxy-2.1.4启动失败,报错ProxyServerError: The Browsermob-Proxy server process failed to start
报错信息:ProxyServerError: The Browsermob-Proxy server process failed to start. Check <_io.TextIOWrap ...
- Ubuntu 20.04 双系统安装完整教程
1.查看电脑的信息 1.1 查看BIOS模式 "win+r"快捷键进入"运行",输入"msinfo32"回车,出现以下界面,可查看BIOS模 ...
- 图床、云对象存储、CDN业务:“自定义 CDN 加速域名” 与 “自定义源站域名” 的区别
参考: https://developer.qiniu.com/kodo/8622/dev-the-binding-source-domain-name ----------------------- ...
- element-UI tree树形控件 修改小三角图标
.el-tree /deep/ .el-tree-node__expand-icon.expanded{ -webkit-transform: rotate(0deg); transform: rot ...