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控件的使用,如需转载请自行联系原博主。



目录
相关文章
|
4月前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
70 0
|
4月前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
411 0
|
存储 小程序 前端开发
【易售小程序项目】小程序私聊页面完善(带尾巴聊天气泡组件封装、滑至顶端获取历史聊天数据逻辑优化)【后端基于若依管理系统开发】
【易售小程序项目】小程序私聊页面完善(带尾巴聊天气泡组件封装、滑至顶端获取历史聊天数据逻辑优化)【后端基于若依管理系统开发】
69 0
|
存储 前端开发 Java
案例开发-文件管理服务开发(一)| 学习笔记
快速学习案例开发-文件管理服务开发。
案例开发-文件管理服务开发(一)| 学习笔记
|
前端开发 Java 开发者
案例开发-文件管理服务开发(二)| 学习笔记
快速学习案例开发-文件管理服务开发。
案例开发-文件管理服务开发(二)| 学习笔记
|
前端开发 数据库 数据安全/隐私保护
总结项目功能特点(后台系统1)| 学习笔记
快速学习 总结项目功能特点(后台系统1)
174 0
总结项目功能特点(后台系统1)| 学习笔记
|
Python Windows
保姆级别指导给UI应用添加菜单【实战分享】
正式的Python专栏第16篇,同学站住,别错过这个从0开始的文章!
236 0
保姆级别指导给UI应用添加菜单【实战分享】
|
数据安全/隐私保护 开发框架 数据管理