WPF中非递归(无后台代码)动态实现TreeView

这篇具有很好参考价值的文章主要介绍了WPF中非递归(无后台代码)动态实现TreeView。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在UI界面中,树形视图是比较常用的表示层级结构的方式,WPF中提供了TreeView控件。对于TreeView控件的基本使用已经有很多文章。大都是介绍如何在XAML中使用硬编码的固定信息填充Treeview控件,或者是后台代码递归遍历数据源,动态创建TreeView。这里我想介绍一下如何只通过XAML标记,不用一行后台代码遍历数据实现TreeView。

技术要点与实现

本文的技术关键点是层级式数据模板HierarchicalDataTemplateHierarchicalDataTemplate是一个特殊的DataTemplate,它能够包装第二层模板。通过ItemsSource属性查找下一层级的数据集合,并将它提供给第二层模板。这样描述可能有点晦涩。接下来举例进行描述。

首先假设一个应用场景。用树形结构展现一个地区所有的学校->年级->班级->学生。首先定义几个Model

public class School : ObservableObject
{
    private bool _isOpen;
    /// <summary>
    /// 获取或设置是否展开
    /// </summary>
    [System.Xml.Serialization.XmlIgnore]
    public bool IsOpen { get { return _isOpen; } set { Set(ref _isOpen, value); } }

    private bool _isSelected;
    /// <summary>
    /// 获取或设置是否被选中
    /// </summary>
    [System.Xml.Serialization.XmlIgnore]
    public bool IsSelected { get { return _isSelected; } set { Set(ref _isSelected, value); } }
    
    public string SchoolID { get; set; }
    public string SchoolName { get; set; }
    public ObservableCollection<Grade> listGrade { get; set; }=new ObservableCollection<Grade>() { };
}

public class Grade : ObservableObject
{
    private bool _isOpen;
    [System.Xml.Serialization.XmlIgnore]
    public bool IsOpen { get { return _isOpen; } set { Set(ref _isOpen, value); } }

    private bool _isSelected;
    [System.Xml.Serialization.XmlIgnore]
    public bool IsSelected { get { return _isSelected; } set { Set(ref _isSelected, value); } }
    
    public string GradeID { get; set; }
    public string GradeName { get; set; }
    public ObservableCollection<ClassInfo> ListClass { get; set; }=new ObservableCollection<ClassInfo>() { };
}

public class ClassInfo : ObservableObject
{
    private bool _isOpen;
    [System.Xml.Serialization.XmlIgnore]
    public bool IsOpen { get { return _isOpen; } set { Set(ref _isOpen, value); } }

    private bool _isSelected;
    [System.Xml.Serialization.XmlIgnore]
    public bool IsSelected { get { return _isSelected; } set { Set(ref _isSelected, value); } }

    public string ClassID { get; set; }
    public string ClassName { get; set; }
    public ObservableCollection<Student> Students { get; set; }= new ObservableCollection<Student>() { };

}

public class Student : ObservableObject
{
    private bool _isSelected;
    [System.Xml.Serialization.XmlIgnore]
    public bool IsSelected { get { return _isSelected; } set { Set(ref _isSelected, value); } }

    public string Id { get; set; }
    public string Name { get; set; }
}

接下来根据定义好的Model定义层级式数据模板HierarchicalDataTemplate

<HierarchicalDataTemplate DataType="{x:Type local:School}" ItemsSource="{Binding Path=listGrade}">
    <TextBlock Text="{Binding Path=SchoolName}" />
</HierarchicalDataTemplate>

<HierarchicalDataTemplate DataType="{x:Type local:Grade}" ItemsSource="{Binding Path=ListClass}">
    <TextBlock Text="{Binding Path=GradeName}" />
</HierarchicalDataTemplate>

<HierarchicalDataTemplate DataType="{x:Type local:ClassInfo}" ItemsSource="{Binding Path=Students}">
    <TextBlock Text="{Binding Path=ClassName}" />
</HierarchicalDataTemplate>

<HierarchicalDataTemplate DataType="{x:Type local:Student}">
    <CheckBox Command="{Binding SelectChangeCommand, ElementName=self}" CommandParameter="{Binding}" IsChecked="{Binding IsSelected}">
        <TextBlock Text="{Binding Path=Name}" />
    </CheckBox>
</HierarchicalDataTemplate>

其中最外层数据类型是School,它的下一层数据集合是ObservableCollection<Grade> listGrade,因此HierarchicalDataTemplate中的ItemsSource赋值为listGrade,这里我们再属性控件中只显示学校的名称,因此数据模板只是包含绑定了学校名称SchoolNameTextBlock,如果需要显示其他信息(比如学校年级数量或者学校图标),只需增加相应XAML元素即可。紧接着按照这个方式定义好数据类型Grade,ClassInfo,Student的层级式数据模板即可。
定义好了数据模型和相应的层级式数据模板HierarchicalDataTemplate后,就可以直接把数据元绑定到TreeView上了。假设要绑定的数据源实例是ObservableCollection<School> schools。只需如下调用即可。

<TreeView MaxHeight="480"
            ItemsSource="{Binding schools}"
            VirtualizingPanel.IsVirtualizing="True"
            VirtualizingPanel.VirtualizationMode="Recycling" />

这样使用TreeView是不是特别方便简洁。不用为了展示树形结构,特地定义一个递归类型的数据结构,UI展示全部交给XAML就行。JSON数据反序列化后直接绑定即可(XML或者DateSet也是类似的方法)。避免了递归遍历数据源的操作,也不用考虑递归带来的性能问题。

性能

前边提到不用考虑递归带来的性能问题。那本文介绍的方法对于大量数据的情况下性能到底怎样呢?接下来做一个测试,模拟100W的数据量,具体为240个学校,每个学校3个年级,每个年级20个班,每个班70个学生,总共数据量是240x3x20x70=1008000个。以下是测试结果:
WPF中非递归(无后台代码)动态实现TreeView

从图中可以看到模拟100w数据耗时1.5s,内存增加了160M左右,数据渲染到界面不到1s,内存增加20M左右。结果还是令人满意的。这是因为TreeView支持开启虚拟化(默认是关闭的,设置 VirtualizingPanel.IsVirtualizing="True"开启虚拟化),渲染界面是不会一次把所有UI元素全部创建好,而是根据屏幕上可见区域计算需要渲染的元素个数,创建少量的UI元素,从而减少内存和CPU资源的使用。例如本例中有100w条数据,可见区能显示20条,TreeView只创建了41个UI元素。为什么不是创建20个呢?这是由于为了确保良好的滚动性能,实际会多创建一些UI元素。

TreeView 默认关闭虚拟化,是因为早期的WPF发布版本中的VirtualizingStackPanel不支持层次化数据,虽然现在已支持,但是TreeView默认关闭虚拟化确保兼容性。文章来源地址https://www.toymoban.com/news/detail-647407.html

到了这里,关于WPF中非递归(无后台代码)动态实现TreeView的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WPF绑定数据,增删改后实时更新TreeView/ListView

    WPF的界面的确好看,也引入了很多新功能,和winform相比更先进更强大......那么狗儿蛋,代价是什么? 代价就是WPF学起来比较费力。 数据绑定是WPF的特色之一,可以省去写代码更新UI界面的工作。这次打算做一个管理数据的小软件,自然的我也打算在界面上弄个TreeView,然后把

    2024年02月09日
    浏览(42)
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(5) -- 树列表TreeView的使用

    在我们展示一些参考信息的时候,有所会用树形列表来展示结构信息,如对于有父子关系的多层级部门机构,以及一些常用如字典大类节点,也都可以利用树形列表的方式进行展示,本篇随笔介绍基于WPF的方式,使用TreeView来洗实现结构信息的展示,以及对它的菜单进行的设

    2024年02月08日
    浏览(33)
  • 【Verilog实现FPGA上的信号延迟】—— 用Verilog代码实现将信号延迟N拍,这是FPGA中非常重要的一个操作,可以使数据在不同模块之间精确同步。

    【Verilog实现FPGA上的信号延迟】—— 用Verilog代码实现将信号延迟N拍,这是FPGA中非常重要的一个操作,可以使数据在不同模块之间精确同步。 模块是FPGA中最基本的构建模块。通常一个模块代表一个电路,包括输入、输出和处理逻辑。模块中包含的处理逻辑被称为时序逻辑。

    2024年02月04日
    浏览(62)
  • 数据结构与算法之美学习笔记:41 | 动态规划理论:一篇文章带你彻底搞懂最优子结构、无后效性和重复子问题

    本节课程思维导图: 今天,我主要讲动态规划的一些理论知识。学完这节内容,可以帮你解决这样几个问题:什么样的问题可以用动态规划解决?解决动态规划问题的一般思考过程是什么样的?贪心、分治、回溯、动态规划这四种算法思想又有什么区别和联系? 什么样的问

    2024年02月02日
    浏览(55)
  • JS实现搜索功能页面(可搜索,无需数据库,无后端)

    很多刚学习前端的小伙伴想做一个搜索页面,一看要做后端又要数据库的可能就放弃了,这里给大家带来一个不需要数据库的,也可以使用的搜索功能页面。网页包含了3个功能:搜索框,类别选项,价格进度条。 搜索框是实时搜索的,而且做了不区分英语大小写,也支持中

    2024年02月11日
    浏览(35)
  • 迷路的机器人(递归回溯+动态规划两个方法实现)

    题目: 设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。 示例: 输入: [   [0,0,0],   [0,1,0],   [0,0,0] ] 输出: [[0,0],[0,1],[0,2],[1,2],[2,2]] 解

    2024年02月12日
    浏览(27)
  • RuoYi-Vue-generator 代码生成模块 动态 多数据源切换 前端+后台

    需求场景: 若依框架的30张数据表 和 业务使用的数据表,同数据源,但分开的两个库,原生若依只支持主库的代码生成,故自己修改添加代码来实现 若依多数据源的使用 修改页面ruoyi-uisrcviewstoolgenimportTable.vue el-form 中新增 el-form-item 添加 data 添加方法 ruoyi-uisrcapitool

    2024年02月04日
    浏览(33)
  • C语言实现汉诺塔详细步骤(递归与非递归)及代码

    C语言汉诺塔问题是一个经典的问题,在学习编程的初学者中非常流行。它涉及到了递归的思想,能够帮助我们理解递归的基本原理。 首先,我们来了解一下汉诺塔的问题。汉诺塔问题是指:有三根柱子A,B,C,A柱子上有n个盘子,盘子大小不等,且从下到上由小到大排列,现在

    2023年04月08日
    浏览(27)
  • 打造真实感十足的速度表盘:WPF实现动态效果与刻度绘制

      概述: 这个WPF项目通过XAML绘制汽车动态速度表盘,实现了0-300的速度刻度,包括数字、指针,并通过定时器模拟速度变化,展示了动态效果。详细实现包括界面设计、刻度绘制、指针角度计算等,通过C#代码与XAML文件结合完成。 新建 WPF 项目 : 在 Visual Studio 中创建一个新

    2024年03月16日
    浏览(45)
  • vue3后台管理系统实现动态侧边导航菜单管理(ElementPlus组件)

    记住 一级(el-sub-menu)的都是只是展示的 点击跳转的都是一级下的子级(el-menu-item) 完整展示 1:在登陆功能进行登陆 获取menu列表 注册路由表的时候 把文件进行创建好 因为注册的方法需要获取这个路径 整个router下的main product等等都要创建 2:侧边菜单界面 router/index.ts

    2024年02月16日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包