最近一直在作一些技术性的研究和框架改进工做,博客也落下好几天没有更新了,也该是时候静下心来,总结这段时间的一些技术改进的经验了。和上一阶段的CRM系统开发和技术研究同样,我都喜欢在一个项目或者模块完成后,作一些相关的总结性工做,记录下前一阶段的技术脚印,但愿给本身留下一个脚印快照,同时给读者了解本身的技术动向外,也有所收获。本随笔主要介绍在下拉列表中展现一个列表,以便实现数据结构的良好展现,并能快速选定所需的节点,这个就是TreeListLookupEdit控件的使用。数据结构
首先咱们来看看个人Winform开发框架之权限管理系统模块改进完善后的主界面,而后在介绍其中用到的功能点,以及技术实现。框架
系统用户信息管理界面以下所示。ide
其中用户信息编辑界面以下所示。工具
其中编辑用户信息的界面包括了所属公司、所属部门、直属经理三个输入的内容,为了减小数据量的显示,这几个输入框是经过级联的方式进行展现,也就是说,先选定所属公司,而后在所属公司中列出该公司的部门列表,选定部门后,再经过获取指定部门的人员信息,做为直属经理的人员展现。布局
了解这些逻辑关系后,咱们来看看所属公司的列表展现,以下所示。this
选定了所属公司后,所属部门就根据公司来进行过滤了,以下所示。spa
经过公司和部门的条件,咱们就能够列出有限的人员列表,做为直属经理的人员列表了,这个列表使用普通的下拉列表展现便可,在此再也不赘述。3d
以上的树状结构的下拉列表,在DevExpress控件中是经过TreeListLookupEdit控件进行实现的。code
因为这些所属公司、所属部门的功能模块,通常须要很多代码进行处理,为了更好重用这些模块,咱们经过用户控件的封装方式进行,而后在数据编辑界面上,经过拖动控件方式便可实现布局,并只须要设置或者访问某个属性便可,封装的用户界面控件以下所示。orm
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()); } } .................
上面的介绍内容是基于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这篇文字实现的效果也还不错。
不过可能没有上面的那个效果好一点。
以上这些就是关于级联下拉列表,并在下拉列表里面展现层次关系的树形结构的功能实现和核心代码的操做,本随笔介绍了基于DevExpress样式和传统样式两种方案的实现过程,重点对DevExpress控件中的TreeListLookupEdit控件的实现进行介绍,但愿你们可以在实际工做中用上。