16.8 TreeView控件

导航控件TreeView是一种用来表示树状架构的控件,特别适合用来表示复杂的层级分类。它用于以树形结构显示分层数据,如菜单、目录或文件目录等。与Menu控件相比,它可以组织更复杂的数据结构。本节将针对TreeView控件进行讨论,重点讲解它的各种编程技巧。

16.8.1 TreeView结构

TreeView控件是一种用来表示树状架构的控件,树中的每个项都被称为一个节点。因此,一个完整的树由一个或多个节点构成。这些节点的类型如表16-11所示。一个节点可以同时是父节点和子节点,但是不能同时为根节点、父节点和叶节点。

figure_0569_0448

figure_0569_0449

图 16-25 TreeNode UI元素

Tree View控件的每个节点就是一个TreeNode对象,如图16-25所示。TreeNode对象由以下四个用户界面((U)元素组成,

可以自定义或隐藏这些元素。

1)展开节点指示图标:一个可选图像,指示是否可以展开节点以显示子节点。默认情况下,如果节点可以展开,此图像将为加号(“+”),如果此节点可以折叠,则图像为减号(“-”)。

2)可选的节点图像:可以指定要显示在节点文本旁边的节点图像。

3)节点文本:节点文本是在TreeNode对象上显示的实际文本。节点文本的作用类似于导航模式中的超链接或选择模式中的按钮。

4)与节点关联的可选复选框:复选框是可选的,以允许用户选择特定节点。

在TreeNode中,主要在两个属性中存储数据:Text属性和Value属性。Text属性指定在节点显示的文字,Value属性是获取节点的值。它的常用属性如表16-12所示。

figure_0570_0450

TreeView控件的Nodes包含所有节点(即TreeNode)的集合,可以用设计器为TreeView控件添加节点,也可以使用编程的方式动态添加节点。下面的示例展示了一个简单的TreeView,如下面的代码所示:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server">

<Nodes>

<asp:TreeNode Text="顶级节点"Value="0">

<asp:TreeNode Text="节点1"Value="01">

<asp:TreeNode Text="节点1.0"Value="010">

<asp:TreeNode Text="节点1.0.0"Value="0100"/>

<asp:TreeNode Text="节点1.0.1"Value="0101"/>

<asp:TreeNode Text="节点1.0.2"Value="0102"/>

</asp:TreeNode>

<asp:TreeNode Text="节点1.1"

Expanded="false"Value="011">

<asp:TreeNode Text="节点1.1.0"Value="0110"/>

<asp:TreeNode Text="节点1.1.1"Value="0111"/>

<asp:TreeNode Text="节点1.1.2"Value="0112"/>

<asp:TreeNode Text="节点1.1.3"Value="0113"/>

</asp:TreeNode>

</asp:TreeNode>

</asp:TreeNode>

</Nodes>

</asp:TreeView>


在上面的代码中,将节点“011”的Expanded属性设置为false,即关闭展开。运行结果如图16-26所示。

16.8.2 使用SiteMapDataSource绑定TreeView

对于使用SiteMapDataSource绑定TreeView控件,已经在16.3节做过讲解,这种方法主要用于绑定网站地图文件。绑定方法如图16-27所示。

figure_0571_0451

图 16-26 TreeView示例

figure_0571_0452

图 16-27 使用SiteMapDataSource绑定TreeView

这样,就可以在页面里看见如下代码了:


<asp:SiteMapDataSource ID="SiteMapDataSource1"runat="server"/>

<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

DataSourceID="SiteMapDataSource1">

</asp:TreeView>


16.8.3 使用程序动态建立TreeView节点

TreeView控件经常用来表现复杂的层级式数据结构,因而不同于静态菜单。通常还需要通过程序动态将数据传输给TreeView以建立其节点,并且通过取得节点的关联值执行某些特定的动作。建立节点的语法必须根据节点标签进行引用,假设在网页上建立了一个TreeView控件,并且将其命名为TreeView1,如下面的代码所示:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server">

</asp:TreeView>


有了这个TreeView1之后,可以通过Add方法为TreeView1创建一个根节点,如下面的代码所示:


TreeNode netd=new TreeNode(".NET开发");

TreeView1.Nodes.Add(netd);


当然,还可以利用另外一个版本的方法,将其加入到指定的位置中,而所要加入的位置是由以0为起始值的索引值指定的。如下面程序代码将一个名称为".NET开发"的节点如入到树节点里面的第1个节点的位置,即起始位置。


TreeNode netd=new TreeNode(".NET开发");

TreeView1.Nodes.AddAt(0,netd);


如果想要进一步将指定的节点加到某个节点成为其下的子节点,可以通过ChildNodes.Add方法来添加。如下面的代码所示:


TreeNode netd=new TreeNode(".NET开发");

TreeNode language=new TreeNode(".NET编程语言");

TreeView1.Nodes.Add(netd);

netd.ChildNodes.Add(language);


下面的示例展示了一个完整的TreeView动态创建例子:


public partial class WebForm1:System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

TreeNode netd=new TreeNode(".NET开发");

TreeNode language=new TreeNode(".NET编程语言");

TreeNode cs=new TreeNode("C#");

TreeNode c=new TreeNode("C/C++");

TreeNode vb=new TreeNode("VB");

TreeNode asp=new TreeNode("ASP.NET");

TreeNode net=new TreeNode(".NET版本");

TreeNode net11=new TreeNode(".NET1.1");

TreeNode net20=new TreeNode(".NET2.0");

TreeNode net30=new TreeNode(".NET3.0");

TreeNode net35=new TreeNode(".NET3.5");

TreeNode net40=new TreeNode(".NET4.0");

if(!IsPostBack)

{

TreeView1.Nodes.Add(netd);

//.NET开发

netd.ChildNodes.Add(language);

netd.ChildNodes.Add(net);

//.NET编程语言

language.ChildNodes.Add(cs);

language.ChildNodes.Add(c);

language.ChildNodes.Add(vb);

language.ChildNodes.Add(asp);

//.NET版本

net.ChildNodes.Add(net11);

net.ChildNodes.Add(net20);

net.ChildNodes.Add(net30);

net.ChildNodes.Add(net35);

net.ChildNodes.Add(net40);

}

}

}


运行上面的代码,结果如图16-28所示。

我们知道,TreeView控件第一次显示时,所有的节点都会出现。因此,除了可以通过在页面或者编程设置TreeNode.Expanded属性为true或false来打开或折叠节点之外,还可以通过设置TreeView.ExpandDepth属性来控制这一行为。例如,如果ExpandDepth是2,则只有前面三层会被显示(第0层、第1层和第2层)。要控制TreeView总共包含多少层(展开的或折叠的),可以使用MaxDataBindDepth属性。MaxDataBindDepth的默认值为1,并且可以查看整个树。但是,如果使用值2,则只会看到起始节点下的两层。如下面的代码所示:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"ExpandDepth="1"runat="server">

</asp:TreeView>


这样,TreeView控件就只能够显示两层了,即0层与1层,如图16-29所示。

figure_0573_0453

图 16-28 使用程序动态建立TreeView节点示例

figure_0573_0454

图 16-29 设置ExpandDepth="1"的显示结果

16.8.4 使用XML数据源绑定TreeView

TreeView控件可以使用XML文档作为数据源,根据XML文档的层次结构显示节点。而XML文档的访问由XmlDataSource控件来完成,从XmlDataSource控件的DataFile属性中指定XML文档路径,然后在TreeView控件中设置与XML文档中的节点的对应关系。下面将通过一个示例程序来演示这一过程。

要使用XML文件作为数据源,首先就得在项目里创建一个XML文档。在这里,在项目的App_Data目录下创建了一个名为“Test.xml”的XML文档,该文档包含三层结构:联系人、地区和负责人。代码如下所示:


<?xml version="1.0"encoding="utf-8"?>

<contact name="区域联系人">

<genre name="华中地区">

<person Text="负责人">

<name>张华</name>

<tel>13511111111</tel>

<mail>13511111111@163.com</mail>

</person>

</genre>

<genre name="华北地区">

<person Text="负责人">

<name>王刚</name>

<tel>13522222222</tel>

<mail>13522222222@163.com</mail>

</person>

</genre>

<genre name="王勇">

<person Text="负责人">

<name>张华</name>

<tel>13533333333</tel>

<mail>13533333333@163.com</mail>

</person>

</genre>

</contact>


创建好Test.xml文档之后,从工具箱选择TreeView控件和XmlDataSource控件拖入设计页面,把XmlDataSource控件DataFile属性设置成“~/App_Data/Test.xml”,并把TreeView控件的DataSourceID属性设为“XmlDataSource1”。如下面的代码所示:


<asp:XmlDataSource ID="XmlDataSource1"runat="server"

DataFile="~/App_Data/Test.xml">

</asp:XmlDataSource>

<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

DataSourceID="XmlDataSource1">

</asp:TreeView>


要想让TreeView控件成功地显示这些XML数据,还需要做这样一个工作,即在首次加载页面的时候,用编程的方式通过TreeNodeBinding对象添加节点与XML文档绑定的对应关系。当然,也可以使用设计器来指定这种对应关系。

TreeNodeBinding类在TreeView控件中定义数据项与该数据项绑定到的节点之间的关系。该类的DataMember属性指定在节点显示的数据源对应XML的节点;ValueField属性对应TreeNode对象的Value属性;Text属性指定向用户显示的文本,如果该属性没有指定,则默认与ValueField属性相同。如下面的代码所示:


public partial class WebForm1:System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if(!IsPostBack)

{

//显示连接虚线

this.TreeView1.ShowLines=true;

//以下是添加节点与数据源绑定的对应关系

//绑定contact

TreeNodeBinding contact=new TreeNodeBinding();

//指定绑定的成员

contact.DataMember="contact";

//取值的字段

contact.ValueField="name";

//添加到树中

this.TreeView1.DataBindings.Add(contact);

//绑定genre

TreeNodeBinding genre=new TreeNodeBinding();

genre.DataMember="genre";

genre.ValueField="name";

this.TreeView1.DataBindings.Add(genre);

//绑定person

TreeNodeBinding person=new TreeNodeBinding();

person.DataMember="person";

person.ValueField="Text";

this.TreeView1.DataBindings.Add(person);

//绑定name

TreeNodeBinding name=new TreeNodeBinding();

name.DataMember="name";

name.ValueField="#InnerText";

this.TreeView1.DataBindings.Add(name);

//绑定tel

TreeNodeBinding tel=new TreeNodeBinding();

tel.DataMember="tel";

tel.ValueField="#InnerText";

this.TreeView1.DataBindings.Add(tel);

//绑定mail

TreeNodeBinding mail=new TreeNodeBinding();

mail.DataMember="mail";

mail.ValueField="#InnerText";

this.TreeView1.DataBindings.Add(mail);

}

}

}


设置好上面的对应关系之后,运行结果如图16-30所示。

16.8.5 使用数据库绑定TreeView

本小节将讨论一个非常实用的示例,即将分类数据从数据库中提取出来,再通过递归技巧根据分类建立TreeView节点。为了实现这个示例,这里仍然使用16.6节中的SiteMap表,如图16-31所示。

figure_0575_0455

图 16-30 使用XML数据源绑定TreeView例子

figure_0575_0456

图 16-31 SiteMap表

准备好数据表之后,需要在页面添加两个控件。如下面的代码所示:


<asp:Label ID="Label1"runat="server"></asp:Label>

<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

OnSelectedNodeChanged="TreeView1_SelectedNodeChanged">

</asp:TreeView>


其中,如果在TreeView控件中选择了一个节点,则会引发OnSelectedNodeChanged事件。因此,可以在OnSelectedNodeChanged事件里处理每次选择节点时需要处理的事件(如更新显示的内容等)。在这里,将OnSelectedNodeChanged事件里被选择的节点显示在Label1控件里。详细代码如下面所示:


public partial class WebForm1:System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if(!IsPostBack)

{

string sqlString="select*from SiteMap";

SqlConnection sqlConn=new SqlConnection(

ConfigurationManager.ConnectionStrings

["SiteMapConnectionString"].ToString());

SqlCommand sqlCmd=new SqlCommand(sqlString, sqlConn);

DataSet dataSet=new DataSet();

SqlDataAdapter sqlDataAdapter=

new SqlDataAdapter(sqlCmd);

sqlDataAdapter.Fill(dataSet);

DataTable dt=dataSet.Tables[0];

SetTreeViewNode(dt, null, null);

}

}

private void SetTreeViewNode(DataTable dt, string parentID,

TreeNode treeNode)

{

DataView dv=dt.DefaultView;

dv.Sort="ParentID";

DataRowView[]drvs=dv.FindRows(parentID);

if(drvs.Length>0)

{

foreach(DataRowView drv in drvs)

{

string id=drv["ID"].ToString();

string title=drv["title"].ToString();

TreeNode newTreeNode=new TreeNode(title, id);

SetTreeViewNode(dt, id, newTreeNode);

SetTreeView(treeNode, newTreeNode);

}

}

}

private void SetTreeView(TreeNode treeNode,

TreeNode newTreeNode)

{

if(treeNode==null)

{

TreeView1.Nodes.Add(newTreeNode);

}

else

{

treeNode.ChildNodes.Add(newTreeNode);

}

}

protected void TreeView1_SelectedNodeChanged(object sender,

EventArgs e)

{

Label1.Text="你选择的节点ID是:"

+TreeView1.SelectedNode.Value

+"——节点标题是:"

+TreeView1.SelectedNode.Text;

}

}


在上面的代码中,SetTreeViewNode与SetTreeView这两个函数分别用来设置TreeView控件的组成节点。其中,SetTreeViewNode接受3个参数:dt为整个分类数据表的数据内容;parentID用来取得所有ParentID字段等于此参数的数据;treeNode则是取得的数据所要附加上去的上层节点。SetTreeView则执行节点的创建动作。

现在回到Page_Load方法,这个事件处理程序在网页加载的时候执行,其中首先取得SiteMap数据表的内容,然后引用SetTreeViewNode方法,将取得的DataTable对象及最上层分类项目的ParentID域值(这里为null)当作参数输入。由于是最上层的分类,因此最后一个参数直接设为null。程序的运行结果如图16-32所示。

figure_0577_0457

图 16-32 使用数据库绑定TreeView的示例

通过数据表字段的关联设计及递归式的运用,就可以在页面上轻松地呈现出一个不限层次的树状架构图,这个技术可以让你设计出非常具有弹性的树状导航架构。

16.8.6 按需填充TreeView

有时候,你的TreeView控件可能需要显示大量的数据,在这种情况下如果采用上面的一次填充所有的节点,会大大增加处理第一次请求的时间,而且还会显著增大页面和视图状态的大小。因此,在这种情况下,你可能并不希望一次填充所有的节点,而是按需要填充相关节点。其实,就按需填充功能来讲,TreeView提供了很好的解决方案,它可以让你在节点展开的时候方便地填充树的分支。更妙的是,你随时可以按需填充树的选定部分。

若要动态填充某个节点,请首先将该节点的PopulateOnDemand属性设置为true。然后,为以编程方式填充节点的OnTreeNodePopulate事件定义一个事件处理方法。通常的事件处理方法会从数据源中检索节点数据,将该数据放入一个节点结构中,然后将该节点结构添加到正在被填充的节点的ChildNodes集合中。通过将TreeNode对象添加到父节点的ChildNodes集合中,可以创建一个节点结构。

其实,TreeView支持两种按需填入节点的技术。当PopulateNodesFromClient属性为true的时候(默认),TreeView执行一个客户端的回调来从你的事件获得它需要的节点,而并不需要回发整个页面。如果PopulateNodesFromClient为false,或者它为true,但TreeView侦测到当前浏览器不支持客户端回调,那么TreeView会触发一次正常的回发并获得相同的结果。唯一的区别是整个页面会在浏览器里刷新,产生一个略微不平滑的界面。(它还允许发生另一个页面事件,如控件变化事件。)

下面将通过一个示例来展示如何使用OnTreeNodePopulate事件来实现按需填充的功能。页面的TreeView控件定义如下:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

OnTreeNodePopulate="TreeView1_TreeNodePopulate">

</asp:TreeView>


在Page_Load事件里,只需要加载一个根节点(即id=0的节点),并将该节点的Populate OnDemand属性设置true。这样,就可以通过响应OnTreeNodePopulate事件从而在它展开时填入该根节点的子节点。如下面的代码所示:


public partial class WebForm1:System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

if(!Page.IsPostBack)

{

string sqlString=

"select id, title from SiteMap where id=0";

DataTable dt=GetData(sqlString);

foreach(DataRow row in dt.Rows)

{

TreeNode tree=

new TreeNode(row["title"].ToString(),

row["ID"].ToString());

tree.PopulateOnDemand=true;

tree.Collapse();

TreeView1.Nodes.Add(tree);

}

}

}

protected void TreeView1_TreeNodePopulate(object sender,

TreeNodeEventArgs e)

{

string sqlString=

"select id, title from SiteMap where ParentID=

"+e.Node.Value;

DataTable dt=GetData(sqlString);

foreach(DataRow row in dt.Rows)

{

TreeNode tree=new TreeNode(row["title"].ToString(),

row["ID"].ToString());

tree.PopulateOnDemand=true;

e.Node.ChildNodes.Add(tree);

}

}

private DataTable GetData(string sqlString)

{

SqlConnection sqlConn=new SqlConnection(

ConfigurationManager.ConnectionStrings

["SiteMapConnectionString"].ToString());

SqlCommand sqlCmd=new SqlCommand(sqlString, sqlConn);

DataSet dataSet=new DataSet();

SqlDataAdapter sqlDataAdapter=

new SqlDataAdapter(sqlCmd);

sqlDataAdapter.Fill(dataSet);

DataTable dt=dataSet.Tables[0];

return dt;

}

}


运行上面的代码,结果如图16-33所示。

注意 当节点的PopulateOnDemand属性设置为true时,必须动态填充该节点。不能以声明方式将另一节点嵌套在它下面;否则将会在页面上出现一个错误。一个给定的节点只按需填充一次。此后,值保存在客户端,同一个节点再次折叠或展开时不会再执行回调。

figure_0579_0458

图 16-33 按需填充TreeView的示例

16.8.7 TreeView样式

除了自身的属性外,TreeView控件还支持每种节点类型的TreeNodeStyle控件的属性。这些样式属性将重写应用于所有节点类型的NodeStyle属性。

如表16-13所示,TreeNodeStyle类的大多数成员均从Style类继承而来。它通过提供某些属性来扩展Style类,这些属性控制节点中文本周围的间距和相邻节点之间的间距。使用Horizontal-Padding属性控制节点中文本左边和右边的间距。类似地,VerticalPadding属性控制节点中文本上方和下方的间距。通过设置NodeSpacing属性,可以控制应用TreeNodeStyle的节点与相邻节点之间的间距。若要控制父节点与子节点之间的间距,请使用ChildNodesPadding属性。

figure_0579_0459

图 16-34 描述了TreeNodeStyle属性的具体样式控制情况:

figure_0579_0460

图 16-34 TreeNodeStyle属性

其中,NodeIndent属性为所有节点指定缩进量级。节点会从呈现TreeView控件的一侧缩进。对于从左向右呈现的区域设置而言,这是指左侧,而对于从右向左呈现的区域设置而言,这是指右侧。

1.把样式应用到节点类型

TreeView控件允许你分别控制不同类型的节点的样式,如根节点、包含其他节点的节点、选定的节点等,如表16-14所示。

figure_0580_0461

如表16-14所示,如果要对树的所有节点应用样式,可以使用TreeView.NodeStyle属性。如下面的代码所示:


<asp:TreeView ID="TreeView1"NodeStyle-ForeColor="Blue"

NodeStyle-VerticalPadding="0"runat="server">

</asp:TreeView>


当一个节点被选中或鼠标悬停于该节点上时,可对该节点应用不同的样式。当某个节点的Selected属性设置为true时,将应用SelectedNodeStyle属性,对于选中的节点,该属性将重写任何未选择的样式属性。当鼠标悬停于某个节点上时,将应用HoverNodeStyle属性。

这些样式属性按以下优先级顺序应用:

1)NodeStyle.

2)RootNodeStyle、ParentNodeStyle或LeafNodeStyle(根据节点类型应用)。如果定义了LevelStyles集合,则其应用优先级同前,并覆盖其他节点样式属性。

3)SelectedNodeStyle.

4)HoverNodeStyle.

2.LevelStyles集合

LevelStyles集合是单独设置各样式属性(如NodeStyle属性)的替代方法。LevelStyles集合可控制处于树视图中特定级别的节点的样式。集合中的第一个样式对应于树视图第一级中的节点的样式。集合中的第二个样式对应于树视图第二级中的节点的样式,依此类推。此属性最常用于生成目录样式导航菜单,其中处于某个特定级别的节点应具有相同的外观,而无论这些节点是否拥有子节点。

为了更好地演示LevelStyles集合的使用方法,下面将16.8.6节中的例子修改如下:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

OnTreeNodePopulate="TreeView1_TreeNodePopulate">

<LevelStyles>

<asp:TreeNodeStyle ChildNodesPadding="10"

Font-Bold="true"Font-Size="12pt"ForeColor="DarkGreen"/>

<asp:TreeNodeStyle ChildNodesPadding="5"

Font-Bold="true"Font-Size="10pt"/>

<asp:TreeNodeStyle ChildNodesPadding="5"

Font-Underline="true"Font-Size="10pt"/>

<asp:TreeNodeStyle ChildNodesPadding="10"

Font-Size="8pt"/>

</LevelStyles>

</asp:TreeView>


运行程序,运行结果如图16-35所示。

3.ShowLines属性

ShowLines属性指定是否显示将子节点连接到父节点的连线。当此属性设置为true时,将显示一条虚线将子节点连接到父节点。如下面的代码所示:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

OnTreeNodePopulate="TreeView1_TreeNodePopulate"

ShowLines="true">

<LevelStyles>

……

</LevelStyles>

</asp:TreeView>


运行上面的页面,结果如图16-36所示。

figure_0581_0462

图 16-35 LevelStyles集合的使用示例

figure_0581_0463

图 16-36 ShowLines属性的使用示例

当然,也可以定义自己的连线图像,连线图像必需放置在一个文件夹中,然后必须将LineImagesFolder属性设置为指向连线图像所在的文件夹就可以了。

4.在节点中使用图片

在TreeView控件中,除了可以通过TreeViewNode.ImageUrl属性为单个节点设置图片之外,还可以通过3个TreeView属性为整个树设置图片。可以为所有折叠的节点((CllapseImageUrl)、所有展开的节点((EpandImageUrl)和所有没有子节点并因此不能展开的节点((NExpandImageUrl)选择要显示的图片。如果设置了这些属性并通过TreeViewNode.ImageUrl属性为特定节点指定了图片,节点的特定图片将优先使用。

如果不想创建自己自定义的节点图片,TreeView还有自带图片。如果要访问这些图片,就要使用TreeView.ImageSet属性,它接收来自TreeViewImageSet的枚举值。每组都包含折叠、展开和没有分支的节点要使用的图片。使用ImageSet属性时,不需要设置任何其他相关的属性。使用示例如下面的代码所示:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

OnTreeNodePopulate="TreeView1_TreeNodePopulate"

ShowLines="true"

ImageSet="BulletedList4">

<LevelStyles>

……

</LevelStyles>

</asp:TreeView>


运行上面的页面,结果如图16-37所示。

figure_0582_0464

图 16-37 在节点中使用图片的示例

16.8.8 添加复选框

若要在TreeView控件中提供多节点选择支持,可以在节点的图像旁边显示复选框。使用ShowCheckBoxes属性可指定哪些节点类型将显示复选框。表16-15列出了此属性的有效值。

figure_0582_0465

例如,如果ShowCheckBoxes属性设置为All,则会为树中的所有节点显示复选框。如下面的代码所示:


<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

OnTreeNodePopulate="TreeView1_TreeNodePopulate"

ShowCheckBoxes="All">

</asp:TreeView>


运行结果如图16-38所示。

figure_0582_0466

图 16-38 ShowCheckBoxes="All"的示例

如果只设置ShowCheckBoxes属性,会存在一个缺陷。如图16-38所示,如果选择“基础资料管理”节点,则它的子节点“员工档案”和“客户档案”不会自动选中。其实,在实际应用中,往往希望选中某个父节点时,它的子节点都被选中,这样可以提高系统的操作效率。

为了改进这个操作缺陷,可以用一段客户端脚本来控制它。如下面的代码所示:


<%@Page Language="C#"AutoEventWireup="true"

CodeBehind="WebForm1.aspx.cs"Inherits="_16_5.WebForm1"%>

<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

<title></title>

<script language="javascript"type="text/javascript">

function client_OnTreeNodeChecked(){

var obj=window.event.srcElement;

var treeNodeFound=false;

var checkedState;

if(obj.tagName=="INPUT"&&obj.type=="checkbox")

{

var treeNode=obj;

checkedState=treeNode.checked;

do{

obj=obj.parentElement;

}while(obj.tagName!="TABLE")

var parentTreeLevel=obj.rows[0].cells.length;

var parentTreeNode=obj.rows[0].cells[0];

var tables=

obj.parentElement.getElementsByTagName("TABLE");

var numTables=tables.length

if(numTables>=1){

for(i=0;i<numTables;i++){

if(tables[i]==obj){

treeNodeFound=true;

i++;

if(i==numTables){

return;

}

}

if(treeNodeFound==true)

{

var childTreeLevel=

tables[i].rows[0].cells.length;

if(childTreeLevel>parentTreeLevel)

{

var cell=

tables[i].rows[0].cells[childTreeLevel-1];

var inputs=

cell.getElementsByTagName("INPUT");

inputs[0].checked=checkedState;

}

else{

return;

}

}

}

}

}

}

</script>

</head>

<body>

<form id="form1"runat="server">

<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

onclick="client_OnTreeNodeChecked();"

OnTreeNodePopulate="TreeView1_TreeNodePopulate"

ShowCheckBoxes="All">

</asp:TreeView>

</form>

</body>

</html>


这样,当选择“基础资料管理”节点时,它的子节点“员工档案”和“客户档案”就会自动选中,如图16-39所示。

figure_0584_0467

图 16-39 节点自动选择的示例

在程序中,若要确定哪些节点的复选框已选定,可以通过循环访问CheckedNodes集合的节点来获取被选中的节点。

下面的示例展示了如何获取被选中节点的值,页面代码如下所示:


<asp:Label ID="Label1"runat="server"></asp:Label>

<asp:TreeView ID="TreeView1"Font-Names="Arial"

ForeColor="Blue"runat="server"

onclick="client_OnTreeNodeChecked();"

OnTreeNodePopulate="TreeView1_TreeNodePopulate"

ShowCheckBoxes="All">

</asp:TreeView>

<asp:Button ID="Button1"runat="server"Text="选择节点"

OnClick="Button1_Click"/>


在Button1_Click事件里,将获取到的选中节点的值与选中节点的父节点的值显示在Label1控件里。如下面的代码所示:


protected void Button1_Click(object sender, EventArgs e)

{

if(TreeView1.CheckedNodes.Count>0)

{

Label1.Text="你选择的节点是:<p>";

foreach(TreeNode node in TreeView1.CheckedNodes)

{

Label1.Text+="节点:"+node.Text;

if(node.Parent!=null)

{

Label1.Text+="——父节点:

"+node.Parent.Text+"<br>";

}

}

}

else

{

Label1.Text="你没有选择任何节点!";

}

}


页面的运行结果如图16-40所示。

注意 用于ShowCheckBoxes属性的枚举类型是标志枚举,它还允许通过按位操作组合值。例如,若要为父节点和叶节点显示复选框,请使用位OR运算符组合TreeNodeType.Parent和TreeNode-Type.Leaf值。

figure_0585_0468

图 16-40 获取选中节点的值的示例