asp.net夜话之十:复合控件和母板页(上)_asp
        本篇要讲述的知识点如下:
TreeView控件
MultiView控件
Javascript方式的选项卡
WiZard控件
MasterPage母板页
TreeView控件
        在我们的开发中经常会遇到一些有树形层次关系的数据,比如显示无限级分类和显示某个文件下的所有文件及文件夹,对于这些带有树形层次关系的数据的显示用TreeView控件是一个比较不错的选择。TreeView控件支持数据绑定也支持以编程的方式动态添加节点。在TreeView控件中每个节点都是一个TreeNode对象,我们可以通过TreeNode对象的Nodes属性来添加其它的TreeNode对象,使之成为这个TreeNode对象的子节点。
        TreeView对象有以下常见属性:
属性名 说明
CheckedNodes 获取选中了复选框的节点
CollapseImageUrl 节点折叠时的图象
DataSource 绑定到TreeView控件的数据源
DataSourceID 绑定到TreeView控件的数据源控件的ID
EnableClientScript 是否允许客户端处理展开和折叠事件
ExpandDepth 第一次显示时所展开的级数
ExpandImageUrl 节点展开的时的图象
NoExpandImageUrl 不可折叠(即无字节点)的节点的图象
PathSeparator 节点之间的值的路径分隔符
SelectedNode 当前选中的节点
SelectedValue 当前选中的值
ShowCheckBoxes 是否在节点前显示复选框
        下面是一个简单的例子。我们的数据都是从一个XML文件中读取的,并将它的节点通过代码的方式添加到TreeView控件中。这个XML文件的物理文件名为area.xml,与下面的asp.net在同一个文件夹下,它的内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<Area>
    <Province iAreaID ="1" cAreaName="北京市"/>
    <Province iAreaID ="2" cAreaName="上海市"/>
    <Province iAreaID ="3" cAreaName="天津市"/>
    <Province iAreaID ="4" cAreaName="重庆市"/>
    <Province iAreaID ="5" cAreaName="湖北省">
        <City iAreaID ="51" cAreaName="武汉市"/>
        <City iAreaID ="52" cAreaName="黄冈市" />
        <City iAreaID ="53" cAreaName="荆州市"/>
        <City iAreaID ="54" cAreaName="武穴市" />
        <City iAreaID ="55" cAreaName="十堰市"/>
        <City iAreaID ="56" cAreaName="黄石市" />
    </Province>
    <Province iAreaID ="6" cAreaName="河北省">
        <City iAreaID ="61" cAreaName="石家庄市"/>
        <City iAreaID ="62" cAreaName="唐山市" />
    </Province>
    <Province iAreaID ="7" cAreaName="山西省">
        <City iAreaID ="71" cAreaName="太原市" />
        <City iAreaID ="72" cAreaName="大同市" />
    </Province>
</Area>
前台代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TreeDemo.aspx.cs" Inherits="TreeDemo" %>
<!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>TreeView控件的例子</title>
</head>
<body>
        <form id="form1" runat="server">
        <div>
                <asp:TreeView ID="treeAreaList" runat="server" AutoGenerateDataBindings="False" OnSelectedNodeChanged="Tree_SelectedNodeChanged">
                </asp:TreeView>
                </div>
        </form>
</body>
</html>
        后台代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Xml.XPath;
public partial class TreeDemo : System.Web.UI.Page
{
        XmlDocument xmlDoc;
void Page_Load() void Page_Load(object sender, EventArgs e)
        {
                if (!Page.IsPostBack)
                {
                        MakeParentNode();
                }
        }    
//生成父结点 #region    //生成父结点    
        /// <summary>    
        /// 生成    
        /// </summary>    
void MakeParentNode() void MakeParentNode()
        {
                treeAreaList.Nodes.Clear();
                xmlDoc = new XmlDocument();
                xmlDoc.Load(Server.MapPath("area.xml "));//动态加载XML文档    
                XmlNodeList nodeList = xmlDoc.SelectSingleNode("Area").ChildNodes;//获取Area节点下的所有子结点    
                //定义Area结点    
                TreeNode topNode = new TreeNode();//定义顶级节点    
                topNode.Text = "area ";
                //    tn.Value = "-1";    
                topNode.Expanded = true;
                treeAreaList.Nodes.Add(topNode);//添加"区域"父结点    
                XmlElement element = null;
                TreeNode treeNode = null;
                //遍历区域下的所有省和直辖市    
                foreach (XmlNode node in nodeList)
                {
                        element = (XmlElement)node;
                        treeNode = new TreeNode();
                        treeNode.Text = element.GetAttribute("cAreaName");//在树控件上显示省或直辖市的名称    
                        treeNode.Value = element.GetAttribute("iAreaID");//获取节点值    
                        treeNode.Expanded = true;
                        topNode.ChildNodes.Add(treeNode);//将省或直辖市级结点添加到顶级节点中    
                        MakeChildNode(node.ChildNodes, treeNode);//通过递归将所有子节点添加到节点集合中    
                }
        }    
        #endregion    
//生成子结点 #region    //生成子结点    
        /// <summary>    
        /// 递归将子节点添加到当前节点下    
        /// </summary>    
        /// <param name="nodeList">XmlNodeList的实例</param>    
        /// <param name="treeNode">要添加子节点的父节点</param>    
void MakeChildNode() void MakeChildNode(XmlNodeList nodeList, TreeNode treeNode)
        {
                XmlElement element = null;
                TreeNode subTreeNode = null;
                //遍历省级节点下的所有市,市辖区    
                foreach (XmlNode node in nodeList)
                {
                        element = (XmlElement)node;
                        subTreeNode = new TreeNode();
                        subTreeNode.Text = element.GetAttribute("cAreaName");//在树控件上显示市或市辖区的名称    
                        subTreeNode.Value = element.GetAttribute("iAreaID");//这里设置节点Value    
                        subTreeNode.Expanded = true;
                        treeNode.ChildNodes.Add(subTreeNode);//将子结点添加到父结点下面    
                        MakeChildNode(node.ChildNodes, subTreeNode);//递归调用本方法    
                }
        }    
        #endregion    
void Tree_SelectedNodeChanged() void Tree_SelectedNodeChanged(object sender, EventArgs e)
        {
                Response.Write("节点的值:" + treeAreaList.SelectedNode.Value+"<br/>");
                Response.Write("节点的路径:" + treeAreaList.SelectedNode.ValuePath + "<br/>");
                Response.Write("节点的数据路径:" + treeAreaList.SelectedNode.DataPath + "<br/>");
        }
}
        有关XML文件的读取是一个比较复杂的问题,这里在代码中仅对程序中所使用的代码进行了详尽的注释。这个页面的运行效果如下:
asp.net夜话之十:复合控件和母板页(上)_dotnet_02
        因为我们给TreeView控件的SelectedNodeChanged事件添加了处理方法,所以当我们点击节点时会进行相关的处理,下面是点击黄冈市的效果:
asp.net夜话之十:复合控件和母板页(上)_dotnet_03
        MultiView控件
MultiView控件是一个比较复杂一点控件,它有点类似于WinForm中的TabControl控件,它是View控件的容器,而View控件则可以当作控件的容器,类似于WinForm中的TabPage控件。
        一次只能设置一个View控件为活动视图,只有处于活动状态的View才会呈现到客户端。如果没有设置任何View为活动视图则不向客户端呈现任何内容。可以通过设计视图或者编码的方式设置活动视图。
        MultiView有两个常见属性:
ActiveViewIndex: 当前活动的View索引,我们通常就是通过设置ActiveViewIndex来控制View的显示的。
Views:当前MultiView控件的View集合
        下面是一个利用MultiView控件实现的类似于Windows应用程序中的选项卡式效果。前台设计代码如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MultiViewDemo.aspx.cs" Inherits="MultiViewDemo" %>
<!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>MultiView应用实例</title>
        <style type="text/css">
        body
{
        font-size: 11pt;
        font-family: 宋体;
}
.mainTitle
{
        font-size: 12pt;
        font-weight: bold;
        font-family: 宋体;
}
.commonText
{
        font-size: 11pt;
        font-family: 宋体;
}
.littleMainTitle
{
        font-size: 10pt;
        font-weight: bold;
        font-family: 宋体;
}
.TopTitle
{
        border: 0px;
        font-size: 10pt;
        font-weight: bold;
        text-decoration: none;
        color: Black;
        display: inline-block;
        width: 100%;        
}
.SelectedTopTitle
{
        border: 0px;
        font-size: 10pt;
        text-decoration: none;
        color: Black;
        display: inline-block;
        width: 100%;
        background-color: White;
}
.ContentView
{
        border: 0px;
        padding: 3px 3px 3px 3px;
        background-color: White;
        display: inline-block;
        width: 390px;
}
.SepBorder
{
        border-top-width: 0px;
        border-left-width: 0px;
        font-size: 1px;
        border-bottom: Gray 1px solid;
        border-right-width: 0px;
}
.TopBorder
{
        border-right: Gray 1px solid;
        border-top: Gray 1px solid;
        background: #DCDCDC;
        border-left: Gray 1px solid;
        color: black;
        border-bottom: Gray 1px solid;
}
.ContentBorder
{
        border-right: Gray 1px solid;
        border-top: Gray 0px solid;
        border-left: Gray 1px solid;
        border-bottom: Gray 1px solid;
        height: 100%;
        width: 100%;
}
.SelectedTopBorder
{
        border-right: Gray 1px solid;
        border-top: Gray 1px solid;
        background: none transparent scroll repeat 0% 0%;
        border-left: Gray 1px solid;
        color: black;
        border-bottom: Gray 0px solid;
}
        </style>
</head>
<body>
        <form id="form1" runat="server">
        <div>
        <fieldset style="width:400px">
                        <legend>MultiView应用实例</legend>
                        <table cellpadding="0" cellspacing="0" width="100%" border="0">
                                <tr>
                                        <td>
                                                <table id="Table1" runat="server" cellpadding="0" cellspacing="0" width="100%" border="0">
                                                        <tr style="height:22px">
                                                                <td class="SelectedTopBorder" id="Cell1" align="center" style="width:80px;">
                                                                        <asp:LinkButton ID="lButtonCompany" runat="server" OnClick="lButtonCompany_Click">公司介绍</asp:LinkButton></td>
                                                                <td class="SepBorder" style="width:2px; height: 22px;"></td>
                                                                <td class="TopBorder" id="Cell2" align="center" style="width:80px;">
                                                                        <asp:LinkButton ID="lButtonProduct" runat="server" OnClick="lButtonProduct_Click">产品介绍</asp:LinkButton></td>
                                                                <td class="SepBorder" style="width:2px; height: 22px;"></td>
                                                                <td class="TopBorder" id="Cell3" align="center" style="width:80px;">
                                                                        <asp:LinkButton ID="lButtonContact" runat="server" OnClick="lButtonContact_Click">联系我们</asp:LinkButton></td>
                                                                <td class="SepBorder" style="width:2px; height: 22px;"></td>
                                                        </tr>
                                                </table>
                                        </td>
                                </tr>
                                <tr>
                                        <td>
                                                <table class="ContentBorder" cellpadding="0" cellspacing="0" width="100%">
                                                            <tr>
                                                                    <td valign="top">
                                                                            <asp:MultiView ID="mvCompany" runat="server" ActiveViewIndex="0">
                                                                                    <asp:View ID="View1" runat="server">
                                                                                                                我们公司是一个正在上升时期的公司。公司目前有中科院计算机院士3人,博士后32人,博士63人,研究生120人,本科生356人,具有非常强大研发实力。</asp:View>
                                                                                    <asp:View ID="View2" runat="server">
                                                                                            我们有丰富的产品线,还可以为用户单独定制。目前有CMS文章发布系统、CRM客户资源关系管理系统、OA自动办公系统、BBS论坛系统及ERP企业资产管理系统等等,正在研发的软件有GPS车辆定位导航系统及工作流定制系统等等。</asp:View>
                                                                                    <asp:View ID="View3" runat="server">
                                                                                            本公司热烈欢迎技术界和销售界的精英加入我们的团队,待遇优厚。我们的联系方式是119,传真是110,客服电话是120,售后电话114。</asp:View>
                                                                             </asp:MultiView>
                                                                    </td>
                                                            </tr>
                                                     </table>
                                             </td>
                                    </tr>
                        </table>
                </fieldset>
        </div>
        </form>
</body>
</html>

        后台程序代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class MultiViewDemo : System.Web.UI.Page
{
void Page_Load() void Page_Load(object sender, EventArgs e)
        {
        }
        /// <summary>    
        /// 点击公司介绍时的css设置    
        /// </summary>    
        /// <param name="sender"></param>    
        /// <param name="e"></param>    
void lButtonCompany_Click() void lButtonCompany_Click(object sender, EventArgs e)
        {
                mvCompany.ActiveViewIndex = 0;
                Cell1.Attributes["class"] = "SelectedTopBorder";
                Cell2.Attributes["class"] = "TopBorder";
                Cell3.Attributes["class"] = "TopBorder";
        }
        /// <summary>    
        /// 点击产品介绍时的css设置    
        /// </summary>    
        /// <param name="sender"></param>    
        /// <param name="e"></param>    
void lButtonProduct_Click() void lButtonProduct_Click(object sender, EventArgs e)
        {
                mvCompany.ActiveViewIndex = 1;
                Cell1.Attributes["class"] = "TopBorder";
                Cell2.Attributes["class"] = "SelectedTopBorder";
                Cell3.Attributes["class"] = "TopBorder";
        }
        /// <summary>    
        /// 点击联系我们时的css设置    
        /// </summary>    
        /// <param name="sender"></param>    
        /// <param name="e"></param>    
void lButtonContact_Click() void lButtonContact_Click(object sender, EventArgs e)
        {
                mvCompany.ActiveViewIndex = 2;
                Cell1.Attributes["class"] = "TopBorder";
                Cell2.Attributes["class"] = "TopBorder";
                Cell3.Attributes["class"] = "SelectedTopBorder";
        }
}
        页面在设计视图状态下的效果:
asp.net夜话之十:复合控件和母板页(上)_dotnet_04
        下面分别是点击“公司介绍”、“产品介绍”及“联系我们”时的效果。
“公司介绍”效果
asp.net夜话之十:复合控件和母板页(上)_asp_05
        “产品介绍”效果
asp.net夜话之十:复合控件和母板页(上)_休闲_06
        “联系我们”效果
asp.net夜话之十:复合控件和母板页(上)_dotnet_07
        因为在上面的实现方式中每次点击都会引起向服务器回传,在实际项目中有时候也会采用javascript来实现类似的选项卡式效果。用javascript实现选项卡式效果比使用MultiView控件实现选项卡式效果要复杂一些,因为要编写一些客户端脚本代码。
下面是一个用javascript来实现的选项卡式效果的例子,完全采用输出HTML代码的方式。在这个例子中我们通过css和div来控制当前活动选项卡和非活动选项卡的显示与否及显示样式,疑难部分笔者都做了详尽注释,读者朋友完全可以根据自己的实际需要把代码改造成自己想要的效果。
        以下是设计部分代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="JavaScriptMenu.aspx.cs" Inherits="JavaScriptMenu" %>
<!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>JavaScript实现的选项卡式效果</title>
        <script language="javascript" type="text/javascript">
        function Show_Sub(id_num,num,obj)
        {    
                for(var i = 0;i <= 9;i++)
                {
                        if(GetObj("tabb" + id_num + i))
                        {
                                GetObj("tabb" + id_num + i).className = 'guide2';
                        }
                        if(GetObj("subb" + id_num + i))
                        {
                                GetObj("subb" + id_num + i).style.display = 'none';
                        }
                }
                if(GetObj("tabb" + id_num + num))
                {
                        GetObj("tabb" + id_num + num).className = 'guide1';
                }
                if(GetObj("subb" + id_num + num))
                {
                        GetObj("subb" + id_num + num).style.display = 'block';
                }
        }
        function GetObj(objName)
        {
                if(document.getElementById)
                {
                        return eval('document.getElementById("' + objName + '")');
                }
                else
                {
                        return eval('document.all.' + objName);
                }
        }
</script>
<style type="text/css">
.guide1 {
cursor: hand;
color: #003399;
background-color:#3399FF;
font-weight: bold;
text-decoration: none;
border-right: 1px solid #A2C0FE;
height: 25px;
line-height: 25px;
}
.guide2 {
cursor: hand;
border-right: 1px solid #A2C0FE;
line-height: 25px;
}
.24line {line-height: 24px;}
.pad5 {padding:5px;}
.padtop2 {padding-top:2px;}
.padtop5 {padding-top:5px;}
.t {border-top: 1px solid #A2C0FE;}
.b {border-bottom: 1px solid #A2C0FE;}
.l {border-left: 1px solid #A2C0FE;}
.r {border-right: 1px solid #A2C0FE;}
.right{
float:right;
color: #999999;
}
.left{
float:left;
color: #999999;
}
</style>
</head>
<body>
        <form id="form1" runat="server">
        <div>
        <%=GetUserPanel(0) %>
        </div>
        </form>
</body>
</html>
        下面是后台代码:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Data.SqlClient;
public partial class JavaScriptMenu : System.Web.UI.Page
{
        protected void Page_Load(object sender, EventArgs e)
        {
        }
        //在本页面中多次要查询数据库,为了简单起见,把对数据库的查询操作提出来作为一个单独的方法    
        //这个方法会根据查询SQL语句的不同而返回不同数据的DataTable    
        private DataTable GetDataTable(string sql)
        {
                SqlConnection connection = new SqlConnection("Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa");
                SqlCommand command = new SqlCommand(sql, connection);
                SqlDataAdapter adapter = new SqlDataAdapter(command);
                DataTable data = new DataTable();
                adapter.Fill(data);
                return data;
        }
        /// <summary>    
        /// 按照UserName字段的首字母顺序查找用户,并以类似于选项卡的方式显示出来    
        /// 说明:在实际项目中可能一个页面要输出多个选项卡式效果,可以以不同的type来区分    
        /// 以达到公用一个方法的目的    
        /// </summary>    
        /// <param name="type">类别编号</param>    
        /// <returns></returns>    
        public string GetUserPanel(int type)
        {
                //因为多次需要操作字符串,为提高性能使用了System.Text.StringBuilder类而非string类    
                StringBuilder text = new StringBuilder(4096);
                //表头    
                text.AppendLine("<!--------start----->");
                text.AppendLine("<table width=\"400\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
                text.AppendLine("<tr>");
                text.AppendLine("<td height=\"168\" valign=\"top\" class=\"padtop2\"><table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
                text.AppendLine("<tr>");
                text.AppendLine("<td height=\"168\" valign=\"top\" class=\"pad5 24line b l t r\">\n<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
                text.AppendLine("<tr>");
                text.AppendLine("<td><table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"l t b\">\n");
                text.AppendLine("<tr>");
                //这里仅列出UserName字段首字母为'c','d','l','z'的用户    
                char[] firstChar=new char[]{'c','d','l','z'};    
                #region 输出选项卡标签    
                for (int i = 0; i < firstChar.Length; i++)
                {
                        text.AppendLine("<td    class=\"guide" + ((i + 1) >= 2 ? 2 : 1) + "\" id=\"tabb" + type + "" + i + "\" + type + "," + i + ",this) align=\"center\">" + firstChar[i] + "</td>");
                }    
                #endregion    
                text.AppendLine("</tr></table>");
                text.AppendLine("</td></tr><tr><td class=\"padtop5\">");    
                #region 输出每个选项卡下的用户    
                for (int i = 0; i < firstChar.Length; i++)
                {
                        if (i == 0)
                        {
                                text.AppendLine("<div id=\"subb" + type + i + "\"    class=\"24line\">\n");
                        }
                        else
                        {
                                text.AppendLine("<div id=\"subb" + type + i + "\"    style=\"DISPLAY: none\"    class=\"24line\">\n");
                        }
                        DataTable dataPersonList = GetDataTable("select UserName,RealName from UserInfo where UserName like '" + firstChar[i] + "%'");
                        DataRow row = null;
                        //输出每个用户的信息    
                        for (int j = 0; j < dataPersonList.Rows.Count; j++)
                        {
                                row = dataPersonList.Rows[j];                                
                                text.AppendLine("<div class=\"left\">" + row["UserName"].ToString() + "</div>");
                                text.Append("<div class=\"right\">" + row["RealName"].ToString() + "</div>");
                                text.AppendLine("</br>");
                        }
                        text.AppendLine("</div>");
                }    
                #endregion    
                text.AppendLine("</td>\n</tr>\n</table>\n</td>\n</tr></table></td></tr></table>");
                text.AppendLine("<!------end--->");
                return text.ToString();
        }
}
        这个程序显示效果如下:
asp.net夜话之十:复合控件和母板页(上)_休闲_08
        点击“z”选项卡时的效果:
asp.net夜话之十:复合控件和母板页(上)_复合控件_09
        用Javascript实现的选项卡式效果比用MultiView控件实现同样的效果要复杂很多,但是它有一个有点就是在选项卡之间切换时不用每次刷新页面和读取数据库。
        WiZard控件
WiZard控件非常类似于我们常见的Windows中的向导控件,用于分步骤收集用户提交的数据。
        下面是拖入一个WiZard控件到空白页面的效果:
asp.net夜话之十:复合控件和母板页(上)_休闲_10
        和MultiView类似,WiZard是一个WizardStepBase的容器,每个WizardStepBase类似于一个View。与MultiView不同的是,WizardStepBase上显示有上下步骤之间的导航,我们可以控制当前WizardStepBase中的导航样式,这可以通过WizardStepBase的StepType属性来控制。如果进行设置,那么每个WizardStepBase的StepType属性为Auto。下面列出了WizardStepBase的StepType属性的所有可能值:
StepType值 显示行为和结果
WizardStepType.Auto 由声明该WizardStepBase的顺序决定
WizardStepType.Complete 整个步骤最后一步,不显示任何导航按钮
WizardStepType.Finish 收集数据的最后一步,显示“完成”导航按钮
WizardStepType.Start 要显示的第一个步骤,不显示“上一步”导航按钮
WizardStepType.Step 介于第一个和最后一个步骤,显示“上一步”、“下一步”按钮