winform如何实现将数据库数据加载到树上

一、简介

对于winform中如何加载xml生成目录树,在前边一篇文章“c#如何实现从xml中加载树目录,并且显示完整的Text”中我已经写了详细的过程。但是有些时候我们不可能将大量的数据存储到xml中,原因是,xml一般用于小数据量的传递。而大数据的存储与传递我们一般用专门的数据库管理工具作为传递的介质。在此,声明一点是,对于大数据量的传递,我们在这里不考虑速率传递快慢问题,我们举例只是实现最基本的功能,这样也方便和我一样的初学者理解。

好了,说了这么多废话,开始正式进入我们这篇文章的正题:

“ winform如何实现将数据库数据加载到树上”?

为了更好的展示我们想要的结果,我先把我之前做过的一个系统的这个功能实现图展示给大家,效果图如下所示:

好了,效果图已经展示!如果这是你想要的效果,那么接下来我将以代码的形式告诉你如何制作这种树结构。

二、实现过程详解

为了实现以上的效果,我们需要做的工作可以分为以下两步:

  1. 构建数据库

    对于构建的数据库,我们需要特别进行制作。因为我们要展示成一级的目录形式,因此在构建数据库数据时,需要将各数据之间的关系说明清楚–编码规则。

    在这里我不妨说一下我构建此树的编码规则,大家也可以相互学习一下:

    1.1. 编码规则

    对于不同的项目而言,编码的位数是具体情况具体看待的,这里我的编码用的方式是–前缀的方式。

    我在定义编码位数时考虑到不同类别,不同级别,具体哪个三部分。

    编码规则: 1+12+4

    **1:首位,区分类别。这里我分了:经济组织、社会组织、还是行政区

    **12:行政区编码。

    它具体又是这样分的:4+2+3+3

    4:前四位是市级

    2:这两位是县(市/区)级

    3:这三位是镇(乡/街道/办事处)级

    3:这三位是村(城市社区/农村社区)级

    **4:具体哪种类别,哪个级别下的哪个组织

    我将这个字段定义为:orgID.

    我们仅有了这个字段还是无法进行构建树的,我们还需要name字段(用于显示text),还需要parent字段(用于进行构建各数据之间的联系–继承关系)。当然,你可以根据你的需要构建你所需要的字段,这里我就不再多说了。我构建好的该表如下图所示:

    这里我们主要看的就是它parent如何。通过此图,我相信对于个数据之间的继承关系,大家已经熟悉了。好了,我们创建好数据库后,接下来就是代码的舞台了。

  2. 构建TreeView

    如何构建一个TreeView?这是另一个比较关键的问题。

    我这里用了visual studio中自带的控件:TreeView控件。这里我不妨啰嗦一下,将我的设计图展示给大家,方便初学者理解:

    是不是看起来很简单呢?好了接下来我们就要构建这个TreeView树了。

    2.1. 获得数据

    对于如何从数据库中获取数据这个我这里就不做说明了,我这里是以xml形式从服务器端传递给客户端的,用DataTable对象来存储。这里我做的是DataGridView某个单元格点击时,弹出这个Organizations树,因此我们还需要用一个·DataRow来记录是DataGridView的哪行数据。

    具体从DataGridView中到DataRow中可以用这段代码实现:

    dataRowView = gridX.Rows[rowIndex].DataBoundItem as DataRowView;
    dataRow = dataRowView.Row;

这样我们就将获取的数据存在了DataTable对象中,将显示的行数据存在了dataRow中。

通过对构造函数的重载,我们将这两个参数传过来,构造函数如下(另外两个参数,我是针对不同条件进行判断的,可以不用去管):


        public Organizations(DataTable transTable, DataRow transRow, String parent, String cloumnName)
        {
            InitializeComponent();
            orgTable = new DataTable();
            orgTable.TableName = "record";//DataTable表名,客户端和服务器端一致,建立联系
            orgTable = transTable;
            getRow = transRow;
            ParentOrgID = Global.userParentOrg;//Global是我声明的静态类,用户获取各种静态变量。
            userOrgID = Global.userOrgID;
            name = cloumnName;
            functionsParent = parent;
        }

好了接下来我们需要的将数据加载到TreeView控件中,具体代码我们可以卸载Load事件中.具体代码如下:

    private void Organizations_Load(object sender, EventArgs e)
        {
            #region 定义变量
            List<TreeNode> treeNodes;
            // DataRow dataRow;
            DataRow[] dataRows;
            TreeNode treeNode, tempNode;
            NameValueCollection parameter;
            String str;
            TreeNode[] nodes;
            String orgID,parentOrgID;

            #endregion

            #region 创建树
            treeNodes = new List<TreeNode>();
            #region 添加查询根节点

            dataRows = orgTable.Select("[orgID]=\‘" + userOrgID + "\‘");
            treeNode = new TreeNode();
            tag = "orgID={0}&orgName={1}&parent={2}&fullName={3}";
            tag = String.Format(tag, dataRows[0]["orgID"], dataRows[0]["orgName"], dataRows[0]["parent"], dataRows[0]["fullName"]);
            treeNode.Name = Convert.ToString(dataRows[0]["orgID"]);
            treeNode.Text = Convert.ToString(dataRows[0]["orgName"]);
            treeNode.Tag = tag;
            treeNodes.Add(treeNode);//将根节点加入到treeNodes列表中
            treeViewX.Nodes.Add(treeNode);//这句话就是加载TreeView中的根节点。
            #endregion

            #region 添加子节点

            while (treeNodes.Count > 0)
            {
                treeNode = treeNodes[0];
                //每次循环都去掉第一个结点,下次循环就是第二个结点
                treeNodes.Remove(treeNode);
                tag = treeNode.Tag as String;
                parameter = System.Web.HttpUtility.ParseQueryString(tag);
                str = "[parent]=‘{0}‘";
                str = String.Format(str, parameter["orgID"]);
                dataRows = orgTable.Select(str);
                for (int i = 0; i < dataRows.Length; i++)
                {
                    tag = "orgID={0}&orgName={1}&parent={2}&fullName={3}";
                    tag = String.Format(tag, dataRows[i]["orgID"], dataRows[i]["orgName"], dataRows[i]["parent"], dataRows[i]["fullName"]);
                    tempNode = new TreeNode();
                    tempNode.Tag = tag;
                    tempNode.Name = Convert.ToString(dataRows[i]["orgID"]);
                    tempNode.Text = Convert.ToString(dataRows[i]["orgName"]);
                    treeNodes.Add(tempNode);
                    //添加上边所找父节点的子节点
                    treeNode.Nodes.Add(tempNode);//将treeNode下的所有子节点点tempNode加入到它的“麾下”
                }

            }
            #endregion

            #endregion

            #region 将记录的org选中

           //这段代码是判断的根据条件,目的是为了根据条件进行默认的选择。
            if (functionsParent == "F005100")
            {
                if (name == "orgName")
                {
                    parentOrgID = Convert.ToString(getRow["parentOrg"]);
                    nodes = treeViewX.Nodes.Find(parentOrgID, true);//查询具体的node
                    if (nodes.Length > 0)
                    {
                        nodes[0].Checked = true;
                    }

                }
                else if (name == "branchName")
                {
                   orgID = Convert.ToString(getRow["orgID"]);
                    nodes = treeViewX.Nodes.Find(orgID, true);
                    if (nodes.Length > 0)
                    { nodes[0].Checked = true; }
                }
            }
            else
            {
                orgID = Convert.ToString(getRow["orgID"]);
                nodes = treeViewX.Nodes.Find(orgID, true);
                if (nodes.Length > 0)
                { nodes[0].Checked = true; }
            }
            #endregion

        }

其实到这里,加载树已经生成了,接下来我多写一下,点击“OK”,后如何将将数据放到控件中。

    private void okButton_Click(object sender, EventArgs e)
        {
            #region 定义变量
            TreeNode selectedNode;
            List<TreeNode> nodes;
            TreeNode treeNode;
            NameValueCollection paramters;
            #endregion

            #region
            selectedNode = null;
            nodes = new List<TreeNode>();
            //注意TreeView.Nodes是获取的控件中的根节点。
            for (int i = 0; i < treeViewX.Nodes.Count; i++)
            {
                nodes.Add(treeViewX.Nodes[i]);
            }
            //循环遍历,从根节点开始,然后每个节点查看是否被选中。
            while (nodes.Count > 0)
            {
                treeNode = nodes[0];
                nodes.Remove(treeNode);

                if (treeNode.Checked == true)
                {
                    selectedNode = treeNode;
                    break;
                }
                for (int i = 0; i < treeNode.Nodes.Count; i++)
                {
                    nodes.Add(treeNode.Nodes[i]);
                }
            }
            #endregion
            #region 读取信息,并改写数据
            if (selectedNode != null)
            {
                tag = selectedNode.Tag as String;
                paramters = System.Web.HttpUtility.ParseQueryString(tag);

                getRow["orgID"] = paramters["orgID"];
                getRow["orgName"] = paramters["orgName"];
            }
            else
            {
                getRow["orgID"] = "";
                getRow["orgName"] = "";
            }
            this.Close();
            #endregion

        }

至此我们的树基本构建完毕!之所以是基本构建完毕,原因是,当我们点击目录树时会出现如下图所示的问题:

就是我们可以进行多选,但是当我们点击确定时获得的是首个选择项。我们想要的结果是单选,而且可以进行循环的在这个窗体中修改选择项。如何实现呢?

通过msdn查找,我们会发现有个叫“BeforeCheck”的事件(在选中树节点复选框前发生),它的委托是TreeViewCancelEventHandler (BeforeCheck、BeforeCollapse、BeforeExpand 或 BeforeSelect 委托事件方法)。其中备注中有这样一句话: “除非移除了该委托,否则每当发生该事件时就调用事件处理程序。”

也就是说我们其实调用了BeforCheck的默认形式,可以多次调用BeforeCheck事件,也就是我们可以多次点击选择。(其实我们根据备注这句话就可以获取了解答的方法。)

那么我们不禁产生了如下问题:

问题1:如何解决多选?

我们可以通过重新书写BeforeCheck事件,先让其移除,即不可以选择,然后在最后在调用修改的BeforeCheck。

问题2:如何进行在此对话框中修改选择

递归调用

好了,明白了解决方式我们就可以进行重新修改BeforeCheck事件了,具体代码如下:

   private void treeViewX_BeforeCheck(object sender, TreeViewCancelEventArgs e)
        {
            List<TreeNode> nodes;
            Int32 intX;
            TreeNode treeNode;

            //准备手工修改check,先关闭
            treeViewX.BeforeCheck -= new TreeViewCancelEventHandler(treeViewX_BeforeCheck);

            nodes = new List<TreeNode>();
            for (intX = 0; intX < treeViewX.Nodes.Count; intX = intX + 1)
            { nodes.Add(treeViewX.Nodes[intX]); }
//遍历查找
            while (nodes.Count > 0)
            {
                treeNode = nodes[0];
                nodes.Remove(treeNode);
                treeNode.Checked = false;

                for (intX = 0; intX < treeNode.Nodes.Count; intX = intX + 1)
                { nodes.Add(treeNode.Nodes[intX]); }
            }

            //e.Node.Checked = true;

            treeViewX.BeforeCheck += new TreeViewCancelEventHandler(treeViewX_BeforeCheck);//递归调用
        }

在Load事件最后添加:

 treeViewX.BeforeCheck += new TreeViewCancelEventHandler(treeViewX_BeforeCheck);

到此为止,我们的构建树已经完成!

    ----祝好运!

                                2015/05/07
时间: 2024-10-31 04:14:16

winform如何实现将数据库数据加载到树上的相关文章

[Aaronyang] 写给自己的WPF4.5 笔记6[三巴掌-大数据加载与WPF4.5 验证体系详解 2/3]

我要做回自己--Aaronyang的博客(www.ayjs.net) 博客摘要: Virtualizing虚拟化DEMO 和 大数据加载的思路及相关知识 WPF数据提供者的使用ObjectDataProvider 和 XmlDataProvider WPF验证 第一:使用自带的属性SET抛出异常,前台捕捉到异常,描红 第二:我们可以自定义验证规则,替代刚开始的异常捕捉验证 第三:我们可以使用INotifyDataErrorInfo方式,增加异常,并实现了验证通知和还原非法值 第四:我们使用了Er

Android5.1图库Gallery2代码分析数据加载流程

图片数据加载流程. Gallery---->GalleryActivity------>AlbumSetPage------->AlbumPage--------->PhotoPage 相册集                        照片集                 某张图片 1,AlbumSetPage.java private void initializeData(Bundle data) { String mediaPath = data.getString(A

实现虚拟模式的动态数据加载Windows窗体DataGridView控件 .net 4.5 (一)

实现虚拟模式的即时数据加载Windows窗体DataGridView控件 .net 4.5 原文地址 :http://msdn.microsoft.com/en-us/library/ms171624.aspx  译 Q:77811970 实现虚拟模式的原因之一 DataGridView控制只检索数据,因为它是必要的. 这就是所谓的 即时数据加载 . 如果你正在与一个非常大的表在一个远程数据库,例如,您可能希望避免启动延迟,只检索所需的数据显示和检索额外的数据只有当用户新行滚动到视图. 如果客户

Entity Framework Code First实体关联数据加载

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 在项目过程中,两个实体数据之间在往往并非完全独立的,而是存在一定的关联关系,如一对一.一对多及多对多等关联.存在关联关系的实体,经常根据一个实体的实例来查询获取与之关联的另外实体的实例. Entity Framework常用处理数据关联加载的方

浅谈Entity Framework中的数据加载方式

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 如果你还没有接触过或者根本不了解什么是Entity Framework,那么请看这里http://www.entityframeworktutorial.net/EntityFramework-Architecture.aspx,其中的一系列文

数据加载的妙招解析

大数据中怎么来加载数据呢?数据加载应该注意哪些问题呢?关系型数据库和Impala.Hive加载数据有哪些区别呢? 在了解加载数据之前必须明确一个概念"数据验证", Impala和Hive与其他关系型数据库不一样,关系型数据库是在写的时候进行校验,比如我们创建一个表,当去给它加载数据的时候,它会去验证数据以及数据类型是不是符合要求,如果不符合,数据就加载不了. 在Hive和Impala中,它在读的时候进行校验.为什么会这样设计呢?主要是为了提升写的速度和加载的效率.那么,这样检验数据会不

解决考试系统高并发数据加载不正确问题

背景: 现在这版考试系统分为学生考试端和后台管理端.同一登陆页,学生输入学号.密码进入考试界面,管理员输入用户名.密码进入后台管理界面.平时没有学生考试时,后台管理界面学院下拉框可以正确的从数据库读取并加载数据,但有学生考试时,后台管理界面学院下拉框获取的数据有时为空,有时为脏数据. 我们所做的尝试: 1.再现数据加载不正确场景 用LoadRunner压力测试程序模拟255人在线考试的过程,发现当考试人数达到50人时,后台管理界面开始出现上述数据加载不正确问题. 2.验证数据库是否产生了死锁 我

数据加载

关于数据是否使用延迟加载,这里我不评判好或不好.主要还是要看自己系统的业务, 若是显示指定要加载的关联数据,可以一次性奖所有需要数据全部取出,这样就能避免延迟加载而导致的与数据源进行多次交互带来的性能问题. 若暂时不需要该数据,或是不确定是否需要改数据,可以使用延迟加载.当确定需要后在加载它.延迟加载是一种很重要的数据访问特性,可以有效地减少与数据源的交互.从而提升程序性能. 但是滥用延迟加载就可能会不但不能提升软件性能,反而会适得其反. 根据以上的两种情况,我们在底层方法抽象时就需要考虑,该使

GreenPlum数据加载

1. copy命令 对于数据加载,GreenPlum数据库提供copy工具,copy工具源于PostgreSQL数据库,copy命令支持文件与表之间的数据加载和表对文件的数据卸载.使用copy命令进行数据加载,数据需要经过Master节点分发到Segment节点,同样使用copy命令进行数据卸载,数据也需要由Segment发送到Master节点,由Master节点汇总后再写入外部文件,这样就限制了数据加载与卸载的效率,但是数据量较小的情况下,copy命令就非常方便.下面测试通过copy命令实现操