最近一直在做一些技術(shù)性的研究和框架改進(jìn)工作,博客也落下好幾天沒有更新了,,也該是時(shí)候靜下心來(lái),總結(jié)這段時(shí)間的一些技術(shù)改進(jìn)的經(jīng)驗(yàn)了。和上一階段的CRM系統(tǒng)開發(fā)和技術(shù)研究一樣,,我都喜歡在一個(gè)項(xiàng)目或者模塊完成后,做一些相關(guān)的總結(jié)性工作,,記錄下前一階段的技術(shù)腳印,,希望給自己留下一個(gè)腳印快照,同時(shí)給讀者了解自己的技術(shù)動(dòng)向外,,也有所收獲,。本隨筆主要介紹在下拉列表中展示一個(gè)列表,以便實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)的良好展示,,并能快速選定所需的節(jié)點(diǎn),,這個(gè)就是TreeListLookupEdit控件的使用,。
1、界面效果展示
首先我們來(lái)看看我的Winform開發(fā)框架之權(quán)限管理系統(tǒng)模塊改進(jìn)完善后的主界面,,然后在介紹其中用到的功能點(diǎn),,以及技術(shù)實(shí)現(xiàn)。
系統(tǒng)用戶信息管理界面如下所示,。
其中用戶信息編輯界面如下所示,。
其中編輯用戶信息的界面包括了所屬公司、所屬部門,、直屬經(jīng)理三個(gè)輸入的內(nèi)容,,為了減少數(shù)據(jù)量的顯示,這幾個(gè)輸入框是通過(guò)級(jí)聯(lián)的方式進(jìn)行展示,,也就是說(shuō),,先選定所屬公司,然后在所屬公司中列出該公司的部門列表,,選定部門后,,再通過(guò)獲取指定部門的人員信息,作為直屬經(jīng)理的人員展示,。
了解這些邏輯關(guān)系后,,我們來(lái)看看所屬公司的列表展示,如下所示,。
選定了所屬公司后,,所屬部門就根據(jù)公司來(lái)進(jìn)行過(guò)濾了,如下所示,。
通過(guò)公司和部門的條件,,我們就可以列出有限的人員列表,作為直屬經(jīng)理的人員列表了,,這個(gè)列表使用普通的下拉列表展示即可,,在此不再贅述。
以上的樹狀結(jié)構(gòu)的下拉列表,,在DevExpress控件中是通過(guò)TreeListLookupEdit控件進(jìn)行實(shí)現(xiàn)的,。
2、基于DevExpress控件的功能實(shí)現(xiàn)及代碼展示
由于這些所屬公司,、所屬部門的功能模塊,,一般需要不少代碼進(jìn)行處理,為了更好重用這些模塊,,我們通過(guò)用戶控件的封裝方式進(jìn)行,,然后在數(shù)據(jù)編輯界面上,通過(guò)拖動(dòng)控件方式即可實(shí)現(xiàn)布局,,并只需要設(shè)置或者訪問(wèn)某個(gè)屬性即可,,封裝的用戶界面控件如下所示,。
1)所屬公司控件代碼
所屬公司是一個(gè)用戶控件,讓其繼承自XtraUserControl即可,,為了在選擇內(nèi)容后觸發(fā)值的變化事件,,我們定義了一個(gè)事件EventHandler EditValueChanged,這樣我們?cè)趦?nèi)部控件的值變化的時(shí)候,,可以通知外部的界面進(jìn)行處理,。
public partial class CompanyControl : XtraUserControl
{
/// <summary>
/// 選擇的值發(fā)生變化的時(shí)候
/// </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);
}
}
為了實(shí)現(xiàn)列表數(shù)據(jù)的綁定,以及增加圖標(biāo)作為區(qū)分節(jié)點(diǎn),,TreeListLookupEdit控件的數(shù)據(jù)綁定操作是這個(gè)控件的核心所在,。
在下面的代碼邏輯里面,我們通過(guò)獲取公司列表,,然后把它轉(zhuǎn)換為一個(gè)DataTable,,并根據(jù)集團(tuán)、公司的層次給予不同的圖標(biāo),,綁定數(shù)據(jù),,并設(shè)置好控件的KeyFieldName、ParentFieldName,、ValueMember,、DisplayMember幾個(gè)重要屬性即可,如下所示,。
/// <summary>
/// 初始化數(shù)據(jù)
/// </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);
}
//設(shè)置圖形序號(hào)
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";
}
為了方便編輯界面中,,對(duì)所屬公司的賦值與獲取操作,我們需要增加一個(gè)Text屬性和一個(gè)Value屬性,。我們需要重載Text屬性,用來(lái)獲取或設(shè)置所屬公司的名稱,;添加一個(gè)Value屬性,,用來(lái)獲取所屬公司的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)所屬部門的控件代碼
所屬部門的代碼邏輯和所屬公司差不多,,唯一不同的是,所屬部門需要一個(gè)上級(jí)的部門標(biāo)識(shí)(公司ID)作為數(shù)據(jù)的過(guò)濾獲取,,如下所示,。
/// <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,,避免出現(xiàn)節(jié)點(diǎn)的嵌套顯示,,因?yàn)?1已經(jīng)作為了一般節(jié)點(diǎn)的頂級(jí)標(biāo)識(shí)
dr["PID"] = "-1";
dr["Name"] = "無(wú)";
dt.Rows.InsertAt(dr, 0);
//設(shè)置圖形序號(hào)
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)主界面的控件使用
封裝好所屬公司和所屬部門的控件后,,我們就可以通過(guò)在工具箱里面拖動(dòng)控件到主編輯界面里面去了,,這樣我們只需要簡(jiǎn)單對(duì)控件進(jìn)行設(shè)置和賦值即可實(shí)現(xiàn),,減少對(duì)控件邏輯過(guò)多的代碼處理。
數(shù)據(jù)編輯界面中,,控件的使用代碼如下所示,。
a)界面賦值操作
this.txtCompany.Value = info.Company_ID;
this.txtDept.Value = info.Dept_ID;
b)界面數(shù)據(jù)獲取操作
info.Dept_ID = txtDept.Value;
info.DeptName = txtDept.Text;
info.Company_ID = txtCompany.Value;
info.CompanyName = txtCompany.Text;
c)界面事件的處理操作
由于界面上兩個(gè)控件是級(jí)聯(lián)的關(guān)系,因此需要處理他們控件的值發(fā)生變化的事件,,如下所示,。
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))
{
//獲取所屬部門后,,就通過(guò)部門ID來(lái)初始化直屬經(jīng)理的人員列表
InitManagers(txtDept.Value.ToInt32());
}
}
.................
3,、基于傳統(tǒng)Winform界面的控件實(shí)現(xiàn)
上面的介紹內(nèi)容是基于DevExpress的控件組進(jìn)行功能實(shí)現(xiàn)的,有些人可能會(huì)問(wèn),,我使用傳統(tǒng)樣式的界面控件,,這種效果如何實(shí)現(xiàn)呢,其實(shí)如果是使用內(nèi)置的控件,,是比較困難實(shí)現(xiàn)這個(gè)效果的,,但是這樣的界面控件有很多人開發(fā)好組件可以利用的,我在做這個(gè)模塊的時(shí)候,,也考慮到了這一點(diǎn),,因此也針對(duì)這些做了一些搜索查詢,發(fā)現(xiàn)國(guó)外有一個(gè)同行封裝的控件做的非常不錯(cuò),,地址是http://www./blog/archives/477,,上面的效果基本上沒問(wèn)題的。這個(gè)人的博客和下載的例子里面,,沒有使用Demo的代碼,,我自己根據(jù)控件的屬性進(jìn)行了一個(gè)Demo例子的編寫,效果和代碼如下所示,。
總體來(lái)說(shuō),,這個(gè)控件實(shí)現(xiàn)的效果還是非常不錯(cuò)的,例子代碼如下所示,,其節(jié)點(diǎn)和TreeView的操作類似,,通過(guò)ComboTreeNode對(duì)象進(jìn)行添加即可。
private void Form1_Load(object sender, EventArgs e)
{
if (!this.DesignMode)
{
this.comboTreeBox1.Nodes.Clear();
ComboTreeNode parentNode = new ComboTreeNode();
parentNode.Text = "愛奇迪集團(tuán)";
parentNode.Nodes.Add("gz", "廣州分公司");
parentNode.Nodes["gz"].ImageIndex = 1;//通過(guò)名字引用
parentNode.Nodes["gz"].ExpandedImageIndex = 1;//通過(guò)名字引用
ComboTreeNode bjNode = new ComboTreeNode();
bjNode.Name = "bj";
bjNode.Text = "北京分公司";
bjNode.ImageIndex = 1;
bjNode.ExpandedImageIndex = 1;
bjNode.FontStyle = FontStyle.Bold;
bjNode.Nodes.Add("財(cái)務(wù)部");
bjNode.Nodes.Add("市場(chǎng)部");
bjNode.Nodes.Add("人力資源部");
parentNode.Nodes.Add(bjNode);
this.comboTreeBox1.Nodes.Add(parentNode);
comboTreeBox1.ExpandAll();
}
}
除了這個(gè)可以實(shí)現(xiàn)傳統(tǒng)界面效果的下拉樹展現(xiàn)外,,CodeProject上的http://www./Articles/25471/Customizable-ComboBox-Drop-Down這篇文字實(shí)現(xiàn)的效果也還不錯(cuò),。
不過(guò)可能沒有上面的那個(gè)效果好一點(diǎn)。
4,、總結(jié)
以上這些就是關(guān)于級(jí)聯(lián)下拉列表,,并在下拉列表里面展示層次關(guān)系的樹形結(jié)構(gòu)的功能實(shí)現(xiàn)和核心代碼的操作,本隨筆介紹了基于DevExpress樣式和傳統(tǒng)樣式兩種方案的實(shí)現(xiàn)過(guò)程,,重點(diǎn)對(duì)DevExpress控件中的TreeListLookupEdit控件的實(shí)現(xiàn)進(jìn)行介紹,,希望大家能夠在實(shí)際工作中用上。