最近一直在作一些技術性的研究和框架改進工做,博客也落下好幾天沒有更新了,也該是時候靜下心來,總結這段時間的一些技術改進的經驗了。和上一階段的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控件的實現進行介紹,但願你們可以在實際工做中用上。