Winform开发框架之权限管理系统改进的经验总结(1)-TreeListLookupEdit控件的使用

简介:

最近一直在做一些技术性的研究和框架改进工作,博客也落下好几天没有更新了,也该是时候静下心来,总结这段时间的一些技术改进的经验了。和上一阶段的CRM系统开发和技术研究一样,我都喜欢在一个项目或者模块完成后,做一些相关的总结性工作,记录下前一阶段的技术脚印,希望给自己留下一个脚印快照,同时给读者了解自己的技术动向外,也有所收获。本随笔主要介绍在下拉列表中展示一个列表,以便实现数据结构的良好展示,并能快速选定所需的节点,这个就是TreeListLookupEdit控件的使用。

1、界面效果展示

首先我们来看看我的Winform开发框架之权限管理系统模块改进完善后的主界面,然后在介绍其中用到的功能点,以及技术实现。

系统用户信息管理界面如下所示。

其中用户信息编辑界面如下所示。

其中编辑用户信息的界面包括了所属公司、所属部门、直属经理三个输入的内容,为了减少数据量的显示,这几个输入框是通过级联的方式进行展示,也就是说,先选定所属公司,然后在所属公司中列出该公司的部门列表,选定部门后,再通过获取指定部门的人员信息,作为直属经理的人员展示。

了解这些逻辑关系后,我们来看看所属公司的列表展示,如下所示。

选定了所属公司后,所属部门就根据公司来进行过滤了,如下所示。

通过公司和部门的条件,我们就可以列出有限的人员列表,作为直属经理的人员列表了,这个列表使用普通的下拉列表展示即可,在此不再赘述。

以上的树状结构的下拉列表,在DevExpress控件中是通过TreeListLookupEdit控件进行实现的。

2、基于DevExpress控件的功能实现及代码展示 

 由于这些所属公司、所属部门的功能模块,一般需要不少代码进行处理,为了更好重用这些模块,我们通过用户控件的封装方式进行,然后在数据编辑界面上,通过拖动控件方式即可实现布局,并只需要设置或者访问某个属性即可,封装的用户界面控件如下所示。

1)所属公司控件代码

所属公司是一个用户控件,让其继承自XtraUserControl即可,为了在选择内容后触发值的变化事件,我们定义了一个事件EventHandler EditValueChanged,这样我们在内部控件的值变化的时候,可以通知外部的界面进行处理。

    public partial class CompanyControl : XtraUserControl
    {
        /// <summary>
        /// 选择的值发生变化的时候
        /// </summary>
        public event EventHandler EditValueChanged;

        public CompanyControl()
        {
            InitializeComponent();

            this.txtCompany.EditValueChanged += new EventHandler(txtCompany_EditValueChanged);
        }

        void txtCompany_EditValueChanged(object sender, EventArgs e)
        {
            if (EditValueChanged != null)
            {
                EditValueChanged(sender, e);
            }
        }

为了实现列表数据的绑定,以及增加图标作为区分节点,TreeListLookupEdit控件的数据绑定操作是这个控件的核心所在。

在下面的代码逻辑里面,我们通过获取公司列表,然后把它转换为一个DataTable,并根据集团、公司的层次给予不同的图标,绑定数据,并设置好控件的KeyFieldName、ParentFieldName、ValueMember、DisplayMember几个重要属性即可,如下所示。

        /// <summary>
        /// 初始化数据
        /// </summary>
        public void Init()
        {
            DataTable dt = DataTableHelper.CreateTable("ImageIndex|int,ID,PID,Name");
            List<OUInfo> list = BLLFactory<OU>.Instance.GetGroupCompany();
            DataRow dr = null;
            foreach (OUInfo info in list)
            {
                dr = dt.NewRow();
                dr["ImageIndex"] = Portal.gc.GetImageIndex(info.Category);
                dr["ID"] = info.ID.ToString();
                dr["PID"] = info.PID.ToString();
                dr["Name"] = info.Name;
                dt.Rows.Add(dr);
            }



            //设置图形序号
            this.treeListLookUpEdit1TreeList.SelectImageList = this.imageList2;
            this.treeListLookUpEdit1TreeList.StateImageList = this.imageList2;

            this.txtCompany.Properties.TreeList.KeyFieldName = "ID";
            this.txtCompany.Properties.TreeList.ParentFieldName = "PID";
            this.txtCompany.Properties.DataSource = dt;
            this.txtCompany.Properties.ValueMember = "ID";
            this.txtCompany.Properties.DisplayMember = "Name";
        }

为了方便编辑界面中,对所属公司的赋值与获取操作,我们需要增加一个Text属性和一个Value属性。我们需要重载Text属性,用来获取或设置所属公司的名称;添加一个Value属性,用来获取所属公司的ID,如下所示。

        /// <summary>
        /// 公司名称
        /// </summary>
        public override string Text
        {
            get
            {
                return this.txtCompany.Text;
            }
            set
            {
                this.txtCompany.Text = value;
            }
        }

        /// <summary>
        /// 公司ID
        /// </summary>
        public string Value
        {
            get
            {
                string result = "-1";
                if (this.txtCompany.EditValue == null || this.txtCompany.EditValue.ToString() == "0")
                {
                    result = "-1";
                }
                else
                {                  
                    result = this.txtCompany.EditValue.ToString();
                }
                return result;
            }
            set
            {
                this.txtCompany.EditValue = value;
            }
        }

2)所属部门的控件代码

所属部门的代码逻辑和所属公司差不多,唯一不同的是,所属部门需要一个上级的部门标识(公司ID)作为数据的过滤获取,如下所示。

        /// <summary>
        /// 初始化部门信息
        /// </summary>
        public void Init()
        { 
            //InitUpperOU
            DataTable dt = DataTableHelper.CreateTable("ImageIndex|int,ID,PID,Name,HandNo,Category,Address,Note");
            DataRow dr = null;

            if (!string.IsNullOrEmpty(ParentOuID))
            {
                List<OUInfo> list = BLLFactory<OU>.Instance.GetAllOUsByParent(ParentOuID.ToInt32());
                foreach (OUInfo info in list)
                {
                    dr = dt.NewRow();
                    dr["ImageIndex"] = Portal.gc.GetImageIndex(info.Category);
                    dr["ID"] = info.ID.ToString();
                    dr["PID"] = info.PID.ToString();
                    dr["Name"] = info.Name;
                    dr["HandNo"] = info.HandNo;
                    dr["Category"] = info.Category;
                    dr["Address"] = info.Address;
                    dr["Note"] = info.Note;
                    dt.Rows.Add(dr);
                }
            }
            //增加一行空的
            dr = dt.NewRow();
            dr["ID"] = "0"; //使用0代替-1,避免出现节点的嵌套显示,因为-1已经作为了一般节点的顶级标识
            dr["PID"] = "-1";
            dr["Name"] = "";
            dt.Rows.InsertAt(dr, 0);

            //设置图形序号
            this.treeListLookUpEdit1TreeList.SelectImageList = this.imageList2;
            this.treeListLookUpEdit1TreeList.StateImageList = this.imageList2;

            this.txtDept.Properties.TreeList.KeyFieldName = "ID";
            this.txtDept.Properties.TreeList.ParentFieldName = "PID";
            this.txtDept.Properties.DataSource = dt;
            this.txtDept.Properties.ValueMember = "ID";
            this.txtDept.Properties.DisplayMember = "Name";
        }

3)主界面的控件使用

封装好所属公司和所属部门的控件后,我们就可以通过在工具箱里面拖动控件到主编辑界面里面去了,这样我们只需要简单对控件进行设置和赋值即可实现,减少对控件逻辑过多的代码处理。

数据编辑界面中,控件的使用代码如下所示。

a)界面赋值操作

                    this.txtCompany.Value = info.Company_ID;
                    this.txtDept.Value = info.Dept_ID;

b)界面数据获取操作

            info.Dept_ID = txtDept.Value;
            info.DeptName = txtDept.Text;
            info.Company_ID = txtCompany.Value;
            info.CompanyName = txtCompany.Text;

c)界面事件的处理操作

由于界面上两个控件是级联的关系,因此需要处理他们控件的值发生变化的事件,如下所示。

    public partial class FrmEditUser : BaseEditForm
    {
        public FrmEditUser()
        {
            InitializeComponent();

            this.txtCompany.EditValueChanged += new EventHandler(txtCompany_EditValueChanged);
            this.txtDept.EditValueChanged += new EventHandler(txtDept_EditValueChanged);
        }

        void txtCompany_EditValueChanged(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(this.txtCompany.Value))
            {
                //赋值给部门控件,并重新初始化部门列表
                txtDept.ParentOuID = this.txtCompany.Value;
                txtDept.Init();
            }
        }

        void txtDept_EditValueChanged(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(txtDept.Value))
            {
                //获取所属部门后,就通过部门ID来初始化直属经理的人员列表
                InitManagers(txtDept.Value.ToInt32());
            }
        }
.................      

3、基于传统Winform界面的控件实现

上面的介绍内容是基于DevExpress的控件组进行功能实现的,有些人可能会问,我使用传统样式的界面控件,这种效果如何实现呢,其实如果是使用内置的控件,是比较困难实现这个效果的,但是这样的界面控件有很多人开发好组件可以利用的,我在做这个模块的时候,也考虑到了这一点,因此也针对这些做了一些搜索查询,发现国外有一个同行封装的控件做的非常不错,地址是http://www.brad-smith.info/blog/archives/477,上面的效果基本上没问题的。这个人的博客和下载的例子里面,没有使用Demo的代码,我自己根据控件的属性进行了一个Demo例子的编写,效果和代码如下所示。

总体来说,这个控件实现的效果还是非常不错的,例子代码如下所示,其节点和TreeView的操作类似,通过ComboTreeNode对象进行添加即可。

        private void Form1_Load(object sender, EventArgs e)
        {
            if (!this.DesignMode)
            {
                this.comboTreeBox1.Nodes.Clear();

                ComboTreeNode parentNode = new ComboTreeNode();
                parentNode.Text = "爱奇迪集团";
                parentNode.Nodes.Add("gz", "广州分公司");
                parentNode.Nodes["gz"].ImageIndex = 1;//通过名字引用
                parentNode.Nodes["gz"].ExpandedImageIndex = 1;//通过名字引用

                ComboTreeNode bjNode = new ComboTreeNode(); 
                bjNode.Name = "bj";
                bjNode.Text = "北京分公司";
                bjNode.ImageIndex = 1;
                bjNode.ExpandedImageIndex = 1;
                bjNode.FontStyle = FontStyle.Bold;

                bjNode.Nodes.Add("财务部");
                bjNode.Nodes.Add("市场部");
                bjNode.Nodes.Add("人力资源部");

                parentNode.Nodes.Add(bjNode);
                this.comboTreeBox1.Nodes.Add(parentNode);

                comboTreeBox1.ExpandAll();
            }
        }

除了这个可以实现传统界面效果的下拉树展现外,CodeProject上的http://www.codeproject.com/Articles/25471/Customizable-ComboBox-Drop-Down这篇文字实现的效果也还不错。

不过可能没有上面的那个效果好一点。 

4、总结

以上这些就是关于级联下拉列表,并在下拉列表里面展示层次关系的树形结构的功能实现和核心代码的操作,本随笔介绍了基于DevExpress样式和传统样式两种方案的实现过程,重点对DevExpress控件中的TreeListLookupEdit控件的实现进行介绍,希望大家能够在实际工作中用上。

本文转自博客园伍华聪的博客,原文链接:Winform开发框架之权限管理系统改进的经验总结(1)-TreeListLookupEdit控件的使用,如需转载请自行联系原博主。



目录
相关文章
|
3月前
|
数据处理 开发者 C#
WPF数据绑定实战:从零开始,带你玩转数据与界面同步,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据绑定是核心技能之一,它能实现界面元素与数据源的同步更新。本文详细介绍了WPF数据绑定的概念与实现方法,包括属性绑定、元素绑定及路径绑定等技术,并通过示例代码展示了如何创建数据绑定。通过数据绑定,开发者不仅能简化代码、提高可维护性,还能提升用户体验。无论初学者还是有经验的开发者,都能从中受益,更好地掌握WPF数据绑定技巧。
88 0
|
3月前
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
180 0
|
设计模式 Java API
Android组件化开发(七)--从零开始教你分析项目需求并实现
前面几篇文章我们封装了几个组件化功能组件:包括:**网络请求组件,图片加载请求组件,应用保活组件,音乐播放组件封装。** &gt; 每个组件都可以直接拿到自己项目中使用,当然还需根据自己项目要求进行优化。
Android组件化开发(七)--从零开始教你分析项目需求并实现
|
前端开发 Java 开发者
案例开发-文件管理服务开发(二)| 学习笔记
快速学习案例开发-文件管理服务开发。
案例开发-文件管理服务开发(二)| 学习笔记
|
Python Windows
保姆级别指导给UI应用添加菜单【实战分享】
正式的Python专栏第16篇,同学站住,别错过这个从0开始的文章!
231 0
保姆级别指导给UI应用添加菜单【实战分享】
|
存储 C#
WinForm基于插件开发实现多项配置存储
一、课程介绍和实例在线演示 明人不说暗话,跟着阿笨一起玩WinForm。本次分享课程属于《C#高级编程实战技能开发宝典课程系列》中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集、整理和完善此系列课程! 本次分享课程给大家带来一个W...
1848 0
|
存储 前端开发 API
|
数据安全/隐私保护 开发框架 数据管理