潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据

简介: 原文:潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据目前自己对treeview的感慨很多 今天先讲 面对这种 表结构的数据 的其中一种绑定方法,后面多几列其他属性都没关系,例如多个字段, 1  A  0 2  B  0 3  C  0 4  D  1 5  E  2 6  F  4 7  G 1 .
原文: 潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据

目前自己对treeview的感慨很多

今天先讲 面对这种 表结构的数据 的其中一种绑定方法,后面多几列其他属性都没关系,例如多个字段,

1  A  0

2  B  0

3  C  0

4  D  1

5  E  2

6  F  4

7  G 1

...

就是递归型的表结构

然后通过treeview 展示( treeview 的name 叫 tv , collection 是 ObservableCollection<T> 的 一个实例

1.首先你必须需要  要建立一个 跟treeview 结构很相似的一个集合,这里建议用  ObservableCollection<T>   这个集合很特殊,你要记得,例如 tv.ItemsSource = this.collection;  当你这样绑定时,修改collection的属性时就是修改treeview绑定的某些属性

 

2.在做绑定时一定要 搞清楚treeview的item的结构,你想呈现什么样的,每个 treeveiwItem就是一个对象 ,这个对象可以用一个类去替代,或者什么去替代

 

3. 不啰嗦了,说正题,新建一个实体类

例如

   

   /// <summary>
   ////// </summary>
   public class ReportCategoryEntity
   {
       /// <summary>
       /// ID
       /// </summary>
       public int Id { get; set; }
       /// <summary>
       /// 名称
       /// </summary>
       public string Title { get; set; }
       /// <summary>
       ///父节点
       /// </summary>
       public int ParentID { get; set; }


   }

 

这个应该看得懂吧,加入那个递归表 叫 FoodCatagory(菜品目录) 表,现在只要递归显示出来就行了

把他所有行取出来 select * from FoodCatagory,如果其中不止基本的三列,有其他列,例如通过这些列的值  作为控制 treeview显示的样式的条件用 这也是很不错的点子,真的,比如说再加一个图片的地址,如果有个图片地址字典表,这里就存那个表中的字段了,如果其他字段你需要,那你可以继续写在 ReportCategoryEntity 这个类中

 

读出来的所有行封装到  List<ReportCategoryEntity>    lstReportCategoryEntity  ,这个应该会把,如果不会,说明你的oop基础没学好了

 

好了

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Media;

namespace 命名空间
{
    public class TreeCategory : INotifyPropertyChanged
    {
        private ObservableCollection<TreeCategory> children = new ObservableCollection<TreeCategory>();

        public TreeCategory() { }

        public TreeCategory(List<ReportCategoryEntity> totalCategory, int parentID)  //0  根目录
        {
            //Parent = this;
            foreach (ReportCategoryEntity item in totalCategory)
            {
                if (item.ParentID == parentID)
                {
                    TreeCategory tc = new TreeCategory(totalCategory, item.Id);
                    tc.Title = item.Title;
                    children.Add(tc);
                }
            }
        }

        public ObservableCollection<TreeCategory> Children
        {
            get { return this.children; }
        }

        /// <summary>
        /// 显示的名称
        /// </summary>
        private string title;
        public string Title
        {
            get
            {
                return title;
            }
            set
            {
                title = value;
                this.NotifyPropertyChanged("Title");
            }
        }
        /// <summary>
        /// 是否选中
        /// </summary>
        private bool isSelected = false;
        public bool IsSelected
        {
            set
            {
                this.isSelected = value;
                this.NotifyPropertyChanged("IsSelected");
            }
            get { return this.isSelected; }
        }

        /// <summary>
        /// 标题字体颜色
        /// </summary>
        private Brush foregroundBrush = new SolidColorBrush(Colors.Black);
        public Brush ForegroundBrush
        {
            set
            {
                this.foregroundBrush = value;
                this.NotifyPropertyChanged("ForegroundBrush");
            }
            get { return this.foregroundBrush; }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }


    }
}

 

 

接下来再建立一个最重要的 类,用来控制treeview显示的,看似像实体类,但又不像,下面是我建立的,本类下有个本类的集合的属性,还是ObservableCollection集合的,加了 INotifyPropertyChanged 只是为了达到只要修改这个集合的某些属性的值,就可以修改treeview的状态了。

例如我这里添加了 标题字体颜色  ForegroundBrush  这个属性,就是为了达到treeview的每个节点的显示颜色,你在递归的时候就可以根据 ReportCategoryEntity 的某些属性作为条件,然后动态给ForegroundBrush  赋值,要记住,每一个 TreeCategory 类就已经对应了一个 treeviewItem,该类的每一个字段都可以作为 treeview 显示出来的条件,至于前面treeview的样式模板该怎么写,很快你就清楚了

 

现在说一下 xaml 中前台的写法

 <TreeView Name="tv" Width="170" Height="800" MaxHeight="520" BorderThickness="0">
                    <TreeView.ItemContainerStyle>
                        <Style TargetType="TreeViewItem">
                            <Setter Property="TreeViewItem.IsExpanded" Value="True"/>
                            <!--<Setter Property="TreeViewItem.IsSelected" Value="{Binding IsSelected}"/>-->
                            <!--<EventSetter Event="MouseMove" Handler="tree_MouseMove" />-->
                            <!--<EventSetter Event="KeyDown" Handler="treeViewItem_KeyDown" />-->
                            <Setter Property="TreeViewItem.Margin" Value="0,1,0,0"/>
                        </Style>
                    </TreeView.ItemContainerStyle>
                    <TreeView.ItemTemplate>
                        <HierarchicalDataTemplate DataType="{x:Type c:TreeCategory}"  ItemsSource="{Binding Children}">
                            <StackPanel  Margin="-2,0,0,0" Orientation="Horizontal" x:Name="staTree">
                                <CheckBox Content="{Binding Title}" FontSize="14" FontFamily="微软雅黑" Tag="{Binding Children}" IsChecked="{Binding IsSelected}" Foreground="{Binding ForegroundBrush}" Unchecked="ck_Unchecked" Checked="ck_Checked"></CheckBox>
                            </StackPanel>
                            <HierarchicalDataTemplate.Triggers>
                                <DataTrigger Binding="{Binding IsSelected}" Value="true">
                                    <Setter TargetName="staTree" Property="Background" Value="White"/>
                                </DataTrigger>
                            </HierarchicalDataTemplate.Triggers>
                        </HierarchicalDataTemplate>
                    </TreeView.ItemTemplate>

                </TreeView>

重点看  <TreeView.ItemTemplate>  这个节点下面的 ,<TreeView.ItemContainerStyle>用来控制总体显示样式的

 

现在你应该有点清楚了

 

1. 首先你要知道  treeviewItem 对应一个  TreeCategory ,treeview控件每个节点下都有可能有子节点,像一个集合,所以我在TreeCategory 类中又包括了他自己的一个集合,已达到构造出和treeview很像的一个结构,感觉到了吗

2. ReportCategoryEntity  这个实体是  把从数据库读出来的每条数据的一个net样子,一条表中的数据对应一个 ReportCategoryEntity  实体对象,达到封装效果,不一定只有这三个字段,拓展他以达到treeview显示更丰富的效果,而且treeview的模板很好写,可以改造出很多种

3.就是 TreeCategory 类  ,如果以前没有接触xaml语言的可能会有疑问  

public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

为什么会有这堆代码,而且每个属性后面,又调了这个 NotifyPropertyChanged 方法,我不知道原理,但我知道怎么用了,wpf的控件很奇特,不像winform控件或者 asp.net控件那么死,重写个控件很难,这就是为什么wpf 做的桌面软件五花八门,而且很炫,只要你的到控件,不脱离实际,控件都可以变成你想要的控件。又说了好多废话。

最重要的还是我的那个 递归

 public TreeCategory(List<ReportCategoryEntity> totalCategory, int parentID)  //0  根目录
        {
            //Parent = this;
            foreach (ReportCategoryEntity item in totalCategory)
            {
                if (item.ParentID == parentID)
                {
                    TreeCategory tc = new TreeCategory(totalCategory, item.Id);
//加一些你想要的字段,然后在这里赋值吧 tc.Title
= item.Title; children.Add(tc); } } }

 

4.为了达到treeview显示的不同效果,加了数据触发器,这样后台一行代码也不要写,有必要的话,你可以再加一个值转换器吧 ,加一些你想要的数据触发器吧,丰富显示效果,例如根据某个字段作为判断条件,如果是什么,把image 控件的source地址换了,就可以达到不同的节点,显示不同的图片了  ,具体应用有很多

<HierarchicalDataTemplate.Triggers>
                                <DataTrigger Binding="{Binding IsSelected}" Value="true">
                                    <Setter TargetName="staTree" Property="Background" Value="White"/>
                                </DataTrigger>
                    //加一些你想要的数据触发器吧,丰富显示效果,例如根据某个字段作为判断条件,如果是什么,把image 控件的source地址换了,就可以达到不同的节点,显示不同的图片了        
</HierarchicalDataTemplate.Triggers>

 

 

后台绑定

    private ObservableCollection<TreeCategory> collection = new ObservableCollection<TreeCategory>();

     this.collection = new TreeCategory(ctagr, 0).Children;
                treeCategories.ItemsSource = this.collection;
ctagr 是个List<ReportCategoryEntity> 集合

 

先冒个泡

这是我做的一个菜品目录checkbox多选版本的 ,作为导航栏的,例如选中这个目录,列出这个目录下的所有菜,或者计算出这个菜品目录的菜的销售情况等等,扩展一下,部门与员工是挺经典的一个例子

 

至于选中根节点,子节点全部选中,那你可以写在checkbox的事件里,应该会吧,这我就不写了,建议递归吧,应为你不知道他下面有多少个子节点

 

这个我加了checkbox选择的模式,全选,全不选,反选,随选

这个我就再说一点吧,然后来体现ObservableCollection 集合的好处

你不可能修改treeviewItem的属性吧,那个有点傻了

直接修改ObservableCollection 中的 TreeCategory 的IsSelected属性就行了,treeview中自动体现

这里我就只说个全选,全不选 的吧

下面是我写的一个算法

为了防止你粘贴复制,不思考我就上个图吧

反选应该就不用我说了吧,留着思考吧

而且每个 节点的 checkbox都是可以改的,而且你还可以组合控件,例如把很多控件放在stackpanel 中,作为一个treeviewItem

例如每个节点鼠标移上去的效果你都可以很轻松的改的,就看你的技术了,鼠标移上去,我就不说了

再看个图吧

如果你熟悉treeview的话,迅雷看看的这个目录效果很轻松的可以做出来,那个TreeviewItem加载动画也可以做

,这是个 目录下有具体内容的treeview结构,这个如果也用这种MVVM思想的话也可以很轻松的做出来,我做过,多态做的,呵呵,下次有时间的话就再写篇 treeview下面有内容时,该怎么写。

 

我自己感觉迅雷看看有点像 Expander 加 treeview  控件呢?下次做一个迅雷看看左边的目录 制作教程吧,好了,就暂时啰嗦到这里吧

 

 

 

 

 

 

 

 

 

 

 

目录
相关文章
|
4月前
|
C# 开发者 Windows
一款基于Fluent设计风格、现代化的WPF UI控件库
一款基于Fluent设计风格、现代化的WPF UI控件库
101 1
|
4月前
|
C# Windows
WPF中如何使用HandyCotrol控件库
WPF中如何使用HandyCotrol控件库
198 1
|
4月前
|
传感器 C# 监控
硬件交互新体验:WPF与传感器的完美结合——从初始化串行端口到读取温度数据,一步步教你打造实时监控的智能应用
【8月更文挑战第31天】本文通过详细教程,指导Windows Presentation Foundation (WPF) 开发者如何读取并处理温度传感器数据,增强应用程序的功能性和用户体验。首先,通过`.NET Framework`的`Serial Port`类实现与传感器的串行通信;接着,创建WPF界面显示实时数据;最后,提供示例代码说明如何初始化串行端口及读取数据。无论哪种传感器,只要支持串行通信,均可采用类似方法集成到WPF应用中。适合希望掌握硬件交互技术的WPF开发者参考。
81 0
|
4月前
|
C# 前端开发 UED
WPF数据验证实战:内置控件与自定义规则,带你玩转前端数据验证,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据验证是确保输入正确性的关键环节。前端验证能及时发现错误,提升用户体验和程序可靠性。本文对比了几种常用的WPF数据验证方法,并通过示例展示了如何使用内置验证控件(如`TextBox`)及自定义验证规则实现有效验证。内置控件结合`Validation`类可快速实现简单验证;自定义规则则提供了更灵活的复杂逻辑支持。希望本文能帮助开发者更好地进行WPF数据验证。
136 0
|
4月前
|
数据处理 开发者 C#
WPF数据绑定实战:从零开始,带你玩转数据与界面同步,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据绑定是核心技能之一,它能实现界面元素与数据源的同步更新。本文详细介绍了WPF数据绑定的概念与实现方法,包括属性绑定、元素绑定及路径绑定等技术,并通过示例代码展示了如何创建数据绑定。通过数据绑定,开发者不仅能简化代码、提高可维护性,还能提升用户体验。无论初学者还是有经验的开发者,都能从中受益,更好地掌握WPF数据绑定技巧。
95 0
|
4月前
|
C# UED 定位技术
WPF控件大全:初学者必读,掌握控件使用技巧,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,控件是实现用户界面交互的关键元素。WPF提供了丰富的控件库,包括基础控件(如`Button`、`TextBox`)、布局控件(如`StackPanel`、`Grid`)、数据绑定控件(如`ListBox`、`DataGrid`)等。本文将介绍这些控件的基本分类及使用技巧,并通过示例代码展示如何在项目中应用。合理选择控件并利用布局控件和数据绑定功能,可以提升用户体验和程序性能。
74 0
|
4月前
|
开发框架 .NET C#
WPF/C#:显示分组数据的两种方式
WPF/C#:显示分组数据的两种方式
62 0
|
4月前
|
XML C# 数据格式
WPF/C#:如何将数据分组显示
WPF/C#:如何将数据分组显示
39 0
|
4月前
|
前端开发 C#
wpfui:一个开源免费具有现代化设计趋势的WPF控件库
wpfui:一个开源免费具有现代化设计趋势的WPF控件库
148 0
|
4月前
|
C# Windows
WPF/C#:如何显示具有层级关系的数据
WPF/C#:如何显示具有层级关系的数据
56 0