因为项目里需要在ComboBox里的下拉框里填充树状的选择项,我个人感觉最好还可以做到子结点的伸缩,因此颇费了一些功夫,现在大体做了个总结。
1。第一考虑的是下载现成的控件。
网上找了几个:
1)http://www.codeproject.com/cs/miscctrl/customcombos.asp
2)http://www.codetools.com/cs/miscctrl/ComboBoxTree.asp
第一个不好用,第2个可以用,不过总有问题。每次你在加载了ComboBoxTree的页面添加或修改别的控件后,运行就报错,需要在初始化函数里把一个值人工改为空。而且这个控件只能把每项的name的string值呈现树形,而不能把每个ITEM的text和value一一对应,总之用的不顺手,就放弃了。
test
#region test

/**//// <summary>
/// 获取部门列表
/// </summary>
private void getDeptItem()
...{
PoliceArchives.DbConnect.DBAccess selectDeptDBAccess = new PoliceArchives.DbConnect.DBAccess();
string sqlStr = "SELECT * from dept_tab";
selectDeptDBAccess.SelectDataSetCommand= sqlStr;
selectDeptDBAccess.Open();
deptDS= selectDeptDBAccess.GetDataSet;
AddTree(0,(TreeNode)null);

for(int i=0;i<DeptDS.Tables[0].Rows.Count;i++)
...{
if(DeptDS.Tables[0].Rows[i]["dept_prt_no"].ToString()=="")
...{
this.comboBoxTree1.Nodes.Add(DeptDS.Tables[0].Rows[i]["dept_name"].ToString());
}
}
}

// 递归添加树的节点
public void AddTree(int ParentID,TreeNode pNode) 
...{
DataView dvTree = new DataView(deptDS.Tables[0]);
//过滤ParentID,得到当前的所有子节点
dvTree.RowFilter = "[dept_prt_no] = " + ParentID;
foreach(DataRowView Row in dvTree) 
...{
if(pNode == null) 
...{ //'?添加根节点
TreeNode Node = this.comboBoxTree1.Nodes.Add(Row["dept_name"].ToString());
AddTree(Int32.Parse(Row["dept_no"].ToString()),Node); //再次递归
}
else 
...{ //添加当前节点的子节点
TreeNode Node = pNode.Nodes.Add(Row["dept_name"].ToString());
AddTree(Int32.Parse(Row["dept_no"].ToString()),Node); //再次递归
}
}
} 
#endregion
2。用treelistView,鼠标单击columnHeader,则把treeListView的高度变高,鼠标落在别的区域,则高度收缩,columnHeader显示的是当前选择项
treelistView里的每个item都可以把text和value分开一一对应,而listView好象不可以。
/**/
/// <summary>
/// 获取部门列表
/// </summary>
private
void
getDeptItem()
...
{
PoliceArchives.DbConnect.DBAccess selectDeptDBAccess = new oliceArchives.DbConnect.DBAccess();
string sqlStr = "SELECT * from dept_tab";
selectDeptDBAccess.SelectDataSetCommand= sqlStr;
selectDeptDBAccess.Open();
deptDS= selectDeptDBAccess.GetDataSet;
DecenTest.Modularization.Controls.TreeListView.TreeListViewItemCollection itemCollection=new DecenTest.Modularization.Controls.TreeListView.TreeListViewItemCollection();
if(deptDS.Tables[0].Rows.Count>0)
...{
this.treeListView1.Visible=true;
循环遍历表一次,把每项添加成TreeListViewItem#region 循环遍历表一次,把每项添加成TreeListViewItem
for(int i=0;i<deptDS.Tables[0].Rows.Count;i++)
...{
string dept_name=deptDS.Tables[0].Rows[i]["dept_name"].ToString();
int dept_prt_no=(int)deptDS.Tables[0].Rows[i]["dept_prt_no"];
int dept_no=(int)deptDS.Tables[0].Rows[i]["dept_no"];
digit=dept_no/100; //位数控制
int m=0; //image索引
while(digit>0)
...{
digit=digit/100;
m++;
}
DecenTest.Modularization.Controls.TreeListView.TreeListViewItem item=new ecenTest.Modularization.Controls.TreeListView.TreeListViewItem(dept_name,m);
itemCollection.Add(item);
item.Tag=dept_no;
if(dept_prt_no==0)
...{
treeListView1.Items.Add(item);
}
}
#endregion

表再遍历一次,每条记录循环一次TreeListViewItem集合,找出该记录的item和父item#region 表再遍历一次,每条记录循环一次TreeListViewItem集合,找出该记录的item和父item
for(int i=0;i<deptDS.Tables[0].Rows.Count;i++)
...{
string dept_name=deptDS.Tables[0].Rows[i]["dept_name"].ToString();
int dept_prt_no=(int)deptDS.Tables[0].Rows[i]["dept_prt_no"];
int dept_no=(int)deptDS.Tables[0].Rows[i]["dept_no"];
DecenTest.Modularization.Controls.TreeListView.TreeListViewItem childItem=null;
DecenTest.Modularization.Controls.TreeListView.TreeListViewItem parentItem=null;
if(dept_prt_no!=0)
...{
foreach(DecenTest.Modularization.Controls.TreeListView.TreeListViewItem item in itemCollection)
...{
if((int)item.Tag==dept_no)
...{
childItem=item;
}
if((int)item.Tag==dept_prt_no)
...{
parentItem=item;
}
}
parentItem.Items.Add(childItem);
}
}
}
---用treeView实现:
test
#region test 用treeView实现:
System.Windows.Forms.TreeView itemCollection=new TreeView();
if(deptDS.Tables[0].Rows.Count>0)
...{
循环遍历表一次,把每项添加成TreeListViewItem#region 循环遍历表一次,把每项添加成TreeListViewItem
for(int i=0;i<deptDS.Tables[0].Rows.Count;i++)
...{
string dept_name=deptDS.Tables[0].Rows[i]["dept_name"].ToString();
int dept_prt_no=(int)deptDS.Tables[0].Rows[i]["dept_prt_no"];
int dept_no=(int)deptDS.Tables[0].Rows[i]["dept_no"];
int digit=dept_no/100; //位数控制
int m=0; //image索引
while(digit>0)
...{
digit=digit/100;
m++;
}
System.Windows.Forms.TreeNode item=new TreeNode();
itemCollection.Nodes.Add(item);
item.Tag=dept_no;
item.Text=dept_name;
if(dept_prt_no==0)
...{
this.treeView1.Nodes.Add(new TreeNode(dept_name));
this.treeView1.ExpandAll();
}
}
#endregion 
表再遍历一次,每条记录循环一次TreeListViewItem集合,找出该记录的item和父item#region 表再遍历一次,每条记录循环一次TreeListViewItem集合,找出该记录的item和父item
for(int i=0;i<deptDS.Tables[0].Rows.Count;i++)
...{
string dept_name=deptDS.Tables[0].Rows[i]["dept_name"].ToString();
int dept_prt_no=(int)deptDS.Tables[0].Rows[i]["dept_prt_no"];
int dept_no=(int)deptDS.Tables[0].Rows[i]["dept_no"];
System.Windows.Forms.TreeNode childItem=null;
System.Windows.Forms.TreeNode parentItem=null;
if(dept_prt_no!=0)
...{
foreach(System.Windows.Forms.TreeNode item in itemCollection.Nodes)
...{
if((int)item.Tag==dept_no)
...{
childItem=item;
}
if((int)item.Tag==dept_prt_no)
...{
parentItem=item;
}
}
parentItem.Nodes.Add(childItem);
}
}
#endregion
3。用textBox+checkBox(或者button)+listview的方法
具体就是用鼠标事件控制落在checkBox(button)的区域,一旦鼠标释放或点击,则将listView隐藏或显示,其中listView为树状显示。
用listView获取部门列表
#region 用listView获取部门列表
/**//// <summary>
/// 获取部门列表
/// </summary>
private void getDeptItem()
...{
PoliceArchives.DbConnect.DBAccess selectDeptDBAccess = new PoliceArchives.DbConnect.DBAccess();
string sqlStr = "SELECT * from dept_tab";
selectDeptDBAccess.SelectDataSetCommand= sqlStr;
selectDeptDBAccess.Open();
deptDS= selectDeptDBAccess.GetDataSet;
AddTree(0,(TreeNode)null);
}
// 递归添加树的节点
public void AddTree(int ParentID,TreeNode pNode) 
...{
DataView dvTree = new DataView(deptDS.Tables[0]);
//过滤ParentID,得到当前的所有子节点
dvTree.RowFilter = "[dept_prt_no] = " + ParentID;
foreach(DataRowView Row in dvTree) 
...{
if(pNode == null) 
...{ //添加根节点
TreeNode Node = this.treeView1.Nodes.Add(Row["dept_name"].ToString());
Node.Tag=Row["dept_no"].ToString();
AddTree(Int32.Parse(Row["dept_no"].ToString()),Node); //再次递归
}
else 
...{ //添加当前节点的子节点
TreeNode Node = pNode.Nodes.Add(Row["dept_name"].ToString());
Node.Tag=Row["dept_no"].ToString();
AddTree(Int32.Parse(Row["dept_no"].ToString()),Node); //再次递归
}
}
}
private void textBox2_MouseEnter(object sender, System.EventArgs e)
...{
this.treeView1.Visible=true;
this.treeView1.BringToFront(); //把控件置于顶层
}
private void treeView1_MouseLeave(object sender, System.EventArgs e)
...{
this.treeView1.Visible=false;;
}
private void treeView1_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
...{
this.textBox2.Text=this.treeView1.SelectedNode.Text;
}
private void checkBox1_CheckedChanged(object sender, System.EventArgs e)
...{
if(this.checkBox1.Checked==true)
...{
this.treeView1.Visible=true;
this.treeView1.BringToFront(); //把控件置于顶层
}
else
...{
this.treeView1.Visible=false;
}
}
#endregion
4。也是最后采用的方法,就是ComboBox+存储过程,即在存储过程里重新排列所有ITEM,让其成为树形,再显示出来。本来想用SQL自定义函数排序,搞了很久未果,最终还是用存储过程实现。这将在之后的文章里说明。这种方法是本质解决,虽然不能象treeView一样收缩展开,但是前几种方法感觉都是敷衍的障眼法。
本文探讨了在ComboBox中实现下拉树状选项的多种方法,包括使用现成控件、TreeView、ListView以及结合TextBox和CheckBox的解决方案。作者在尝试中遇到的问题和最后选择的存储过程方法进行了详述。

被折叠的 条评论
为什么被折叠?



