使用Asp.net的TreeView来构建用户选择输入
选择优于输入,这是一般人的共识,面对繁多的数据,提供良好的选择界面,一方面增强用户的界面体验,一方面也提高了数据的准确性,更节省了用户的宝贵时间。一般的单项数据选择可以使用
DropdownList
控件来实现,但对于有多个选择性输入,而且输入有层次关系的内容,最好选择
TreeView
控件来实现。
本文介绍如何使用使用
TreeView
控件来有效获取用户的输入,其中涉及到
TreeView
控件的级联选择、去掉节点
HTML
链接变为展开目录、获取选择内容、如何构造数据库的信息变为树形内容以及弹出窗口使用等知识点,本文输入应用级别的例子,希望能做个记号,对己对人,皆为利好
!^_^
本文的经营范围是一个可以输入分类及详细子内容的,由于内容繁多,而且具有一定的层次关系,因此,不适合采用
DropdownList
和
CheckboxList
控件,因此采用了带
CheckBox
属性的
TreeView
控件来辅助用户的输入。
输入界面大致如下所示,用户通过选择按钮,触发弹出对话框,在对话框中放置了
TreeView
控件。
在弹出的对话框中,放置的
TreeView
控件,一个带有
CheckBox
,可以方便用户选择,并且具有级联(通过
Javascript
实现,减少
Post
回发),另外由于内容比较多,我设置了展开的级别层次。
用户通过选择或者反选大类,可以选择或反选其列表下面的所有项目,也可以单独选择子项目。
由于通过Javascript不太好获取并组装返回的内容,本文通过了在后台遍历树的方式对返回值进行处理,然后在父窗体的Javascript中对返回值进行了绑定,使其在界面控件中得以显示指定格式的内容。
以下为
HTML
的代码,其中
OnTreeNodeChecked
为级联
Javascript
函数,
SubmitValue
为对返回值进行绑定的操作。
代码
<
div
class
="search">
<
span
>
<
asp:ImageButton
ID
="btnSelect"
runat
="server"
ImageUrl
="~/Themes/Default/btn_select.gif"
onclick
="btnSelect_Click"
/>
<
asp:ImageButton
ID
="btnClose"
runat
="server"
OnClientClick
="javascript:window.close();return false;"
ImageUrl
="~/Themes/Default/btn_close.gif"
/>
</
span
>
<
table
cellspacing
="0"
cellpadding
="0"
border
="0"
width
="100%">
<
tr
>
<
td
class
="ico">
</
td
>
<
td
class
="form">
<
asp:TreeView
ID
="TreeView1"
runat
="server"
onclick
="OnTreeNodeChecked();"
ShowCheckBoxes
="All"
ShowLines
="True"
ExpandDepth
="1"
Font-Bold
="False"
ForeColor
="#0000CC">
</
asp:TreeView
>
</
td
>
</
tr
>
</
table
>
</
div
>
<
script
language
='javascript'
type
='text/javascript'>
function
OnTreeNodeChecked() {
var
ele = event.srcElement;
if
(ele.type == 'checkbox') {
var
childrenDivID = ele.id.replace('CheckBox', 'Nodes');
var
div = document.getElementById(childrenDivID);
if
(div ==
null
)
return
;
var
checkBoxs = div.getElementsByTagName('INPUT');
for
(
var
i = 0; i < checkBoxs.length; i++) {
if
(checkBoxs[i].type == 'checkbox')
checkBoxs[i].checked = ele.checked;
}
}
}
function
SubmitValue() {
var
val = "";
var
returnVal =
new
Array();
var
inputs = document.all.tags("INPUT");
var
n = 0;
for
(
var
i = 0; i < inputs.length; i++)
//
遍历页面上所有的
input
{
if
(inputs[i].type == "checkbox") {
if
(inputs[i].checked) {
var
strValue = inputs[i].value;
val += strValue + ',';
//returnVal[n] = val;
n = n + 1;
}
}
//if(inputs[i].type="checkbox")
}
//for
window.returnValue = val;
window.close();
}
</
script
>
下面代码是页面的后台代码,其中展示了如何对树进行数据绑定,使其能够显示有层次格式的内容,其中
AddTreeNode
是一个递归函数。
btnSelect_Click
事件处理函数,专门对返回的数据进行组装,以一定的格式显示到客户端的控件输入上。
代码
protected
void
Page_Load(
object
sender, EventArgs e)
{
if
(!
this
.IsPostBack)
{
BindData();
}
}
private
void
BindData()
{
ArrayList scopeTree = BLLFactory<BusinessScope>.Instance.GetTree();
foreach
(BusinessScopeNodeInfo nodeInfo
in
scopeTree)
{
TreeNode node =
new
TreeNode(nodeInfo.Name);
node.SelectAction = TreeNodeSelectAction.Expand;
this
.TreeView1.Nodes.Add(node);
AddTreeNode(node, nodeInfo);
}
}
private
void
AddTreeNode(TreeNode parentNode, BusinessScopeNodeInfo nodeInfo)
{
TreeNode treeNode =
null
;
foreach
(BusinessScopeNodeInfo subNodeInfo
in
nodeInfo.Children)
{
treeNode =
new
TreeNode(subNodeInfo.Name);
treeNode.SelectAction = TreeNodeSelectAction.Expand;
parentNode.ChildNodes.Add(treeNode);
AddTreeNode(treeNode, subNodeInfo);
}
}
protected
void
btnSelect_Click(
object
sender, ImageClickEventArgs e)
{
string
result =
""
;
foreach
(TreeNode parent
in
this
.TreeView1.Nodes)
{
foreach
(TreeNode node
in
parent.ChildNodes)
{
StringBuilder sb =
new
StringBuilder();
foreach
(TreeNode subNode
in
node.ChildNodes)
{
if
(subNode.Checked)
{
sb.AppendFormat(
"{0},"
, subNode.Text);
}
}
if
(sb.Length >
0
)
{
sb.Insert(
0
,
string
.Format(
"{0}("
, node.Text));
sb.Append(
")"
);
result += sb.ToString().Replace(
",)"
,
")"
) +
";"
;
}
else
if
(node.Checked)
{
result += node.Text;
}
}
}
Helper.CloseWin(
this
, result.Trim(
';'
));
}
其中数的数据组装也是需要注意的一个地方,为了提高效率,避免频繁查找数据库,我们先把符合条件的数据放到
DataTable
,然后通过对象的
Select
在内存中查找,这样可以很好的提高递归函数的查找效率。
代码
///
<summary>
///
获取数据树
///
</summary>
///
<returns></returns>
public
ArrayList GetTree()
{
ArrayList arrReturn =
new
ArrayList();
string
sql =
string
.Format(
"Select * From {0} Order By PID, Seq "
, tableName);
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmdWrapper = db.GetSqlStringCommand(sql);
DataSet ds = db.ExecuteDataSet(cmdWrapper);
if
(ds.Tables.Count >
0
)
{
DataTable dt = ds.Tables[
0
];
DataRow[] dataRows = dt.Select(
string
.Format(
" PID = {0}"
, -
1
));
for
(
int
i =
0
; i < dataRows.Length; i++)
{
int
id = Convert.ToInt32(dataRows[i][
"ID"
]);
BusinessScopeNodeInfo menuNodeInfo = GetNode(id, dt);
arrReturn.Add(menuNodeInfo);
}
}
return
arrReturn;
}
private
BusinessScopeNodeInfo GetNode(
int
id, DataTable dt)
{
BusinessScopeInfo menuInfo =
this
.FindByID(id);
BusinessScopeNodeInfo menuNodeInfo =
new
BusinessScopeNodeInfo(menuInfo);
DataRow[] dChildRows = dt.Select(
string
.Format(
" PID={0}"
, id));
for
(
int
i =
0
; i < dChildRows.Length; i++)
{
int
childId = Convert.ToInt32(dChildRows[i][
"ID"
]);
BusinessScopeNodeInfo childNodeInfo = GetNode(childId, dt);
menuNodeInfo.Children.Add(childNodeInfo);
}
return
menuNodeInfo;
}
其中所用到的数据实体如下面两个类所示,其中
BusinessScopeNodeInfo
是对象
BusinessScopeInfo
的进一步封装,方便提供树的基本信息,也就是
BusinessScopeNodeInfo
是一个包含了子类数据的对象,
BusinessScopeInfo
仅仅是数据库对象的映射实体。
代码
///
<summary>
///
BusinessScopeNodeInfo
的摘要说明。
///
</summary>
public
class
BusinessScopeNodeInfo : BusinessScopeInfo
{
private
ArrayList m_Children =
new
ArrayList();
///
<summary>
///
子菜单实体类对象集合
///
</summary>
public
ArrayList Children
{
get
{
return
m_Children; }
set
{ m_Children = value; }
}
public
BusinessScopeNodeInfo()
{
this
.m_Children =
new
ArrayList();
}
public
BusinessScopeNodeInfo(BusinessScopeInfo scopeInfo)
{
base
.Id = scopeInfo.Id;
base
.Name = scopeInfo.Name;
base
.Seq = scopeInfo.Seq;
}
}
代码
[Serializable]
public
class
BusinessScopeInfo : BaseEntity
{
#region
Field Members
private
decimal
m_Id =
0
;
private
decimal
m_Pid = -
1
;
private
string
m_Name =
""
;
private
string
m_Seq =
""
;
#endregion
#region
Property Members
public
virtual
decimal
Id
{
get
{
return
this
.m_Id;
}
set
{
this
.m_Id = value;
}
}
public
virtual
decimal
Pid
{
get
{
return
this
.m_Pid;
}
set
{
this
.m_Pid = value;
}
}
public
virtual
string
Name
{
get
{
return
this
.m_Name;
}
set
{
this
.m_Name = value;
}
}
public
virtual
string
Seq
{
get
{
return
this
.m_Seq;
}
set
{
this
.m_Seq = value;
}
}
#endregion
}
其中的数据格式大致如下
(
本文的例子是在
Oracle
环境中工作的),其实
SqlServer
或者其他数据库也是一样。