asp.net夜话之十:复合控件和母板页
本篇要讲述的知识点如下:
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 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;
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!Page.IsPostBack)
- {
- MakeParentNode();
- }
- }
- #region //生成父结点
- /// <summary>
- /// 生成
- /// </summary>
- protected 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>
- protected 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
- protected 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文件的读取是一个比较复杂的问题,这里在代码中仅对程序中所使用的代码进行了详尽的注释。这个页面的运行效果如下:
因为我们给TreeView控件的SelectedNodeChanged事件添加了处理方法,所以当我们点击节点时会进行相关的处理,下面是点击黄冈市的效果:
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
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- }
- /// <summary>
- /// 点击公司介绍时的css设置
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- protected 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>
- protected 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>
- protected void lButtonContact_Click(object sender, EventArgs e)
- {
- mvCompany.ActiveViewIndex = 2;
- Cell1.Attributes["class"] = "TopBorder";
- Cell2.Attributes["class"] = "TopBorder";
- Cell3.Attributes["class"] = "SelectedTopBorder";
- }
- }
页面在设计视图状态下的效果:
下面分别是点击“公司介绍”、“产品介绍”及“联系我们”时的效果。
“公司介绍”效果
“产品介绍”效果
“联系我们”效果
因为在上面的实现方式中每次点击都会引起向服务器回传,在实际项目中有时候也会采用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 + "/" onmousemove=Show_Sub(" + 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();
- }
- }
这个程序显示效果如下:
点击“z”选项卡时的效果:
用Javascript实现的选项卡式效果比用MultiView控件实现同样的效果要复杂很多,但是它有一个有点就是在选项卡之间切换时不用每次刷新页面和读取数据库。
WiZard控件
WiZard控件非常类似于我们常见的Windows中的向导控件,用于分步骤收集用户提交的数据。
下面是拖入一个WiZard控件到空白页面的效果:
和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 | 介于第一个和最后一个步骤,显示“上一步”、“下一步”按钮 |
在页面中添加一个Wizard控件之后,点击“添加/移除WiZardSteps…”按钮,出现如下界面:
我们可以设置每一个步骤的Title属性,这个属性是显示每个步骤的名称的。然后再添加每个步骤应该显示的内容。
下面以代码模拟一个找回密码的功能,前台代码如下:
- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="WiZardDemo.aspx.cs" Inherits="WiZardDemo" %>
- <!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>WiZard控件用法</title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <asp:Wizard ID="Wizard1" runat="server" ActiveStepIndex="0" Width="400" OnActiveStepChanged="Wizard1_ActiveStepChanged">
- <WizardSteps>
- <asp:WizardStep runat="server" Title="第一步" StepType="Start">
- <table border="0" cellpadding="0" cellspacing="0">
- <tr><td>请输入用户名</td><td><asp:TextBox runat="server" ID="txtUserName"></asp:TextBox></td></tr>
- </table>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" Display="Dynamic"
- ErrorMessage="请输入用户名" ControlToValidate="txtUserName"></asp:RequiredFieldValidator>
- </asp:WizardStep>
- <asp:WizardStep runat="server" Title="第二步" StepType="Step">
- <table border="0" cellpadding="0" cellspacing="0">
- <tr><td>你的密码提示问题</td><td><asp:Label runat="server" ID="lbQuestion"></asp:Label></td></tr>
- <tr><td>你的密码提示答案</td><td><asp:TextBox runat="server" ID="txtAnswer"></asp:TextBox></td></tr>
- </table>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txtAnswer"
- ErrorMessage="请输入密码提示答案"></asp:RequiredFieldValidator>
- </asp:WizardStep>
- <asp:WizardStep runat="server" StepType="Finish" Title="第三步">
- <table border="0" cellpadding="0" cellspacing="0">
- <tr><td>请输入新密码</td><td>
- <asp:TextBox ID="txtPassword" runat="server"></asp:TextBox>
- </td></tr>
- <tr><td>请确认新密码</td><td><asp:TextBox runat="server" ID="txtCPassword"></asp:TextBox></td></tr>
- </table>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="txtPassword"
- Display="Dynamic" ErrorMessage="请输入新密码"></asp:RequiredFieldValidator>
- <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" ControlToValidate="txtCPassword"
- Display="Dynamic" ErrorMessage="请确认新密码"></asp:RequiredFieldValidator>
- <asp:CompareValidator ID="CompareValidator1" runat="server" ControlToCompare="txtPassword"
- ControlToValidate="txtCPassword" ErrorMessage="两次密码不一致"></asp:CompareValidator>
- </asp:WizardStep>
- <asp:WizardStep runat="server" StepType="Complete" Title="第四步">
- 恭喜,密码更改成功。
- </asp:WizardStep>
- </WizardSteps>
- <HeaderTemplate>
- 找回密码
- </HeaderTemplate>
- </asp:Wizard>
- </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 WiZardDemo : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- }
- protected void Wizard1_ActiveStepChanged(object sender, EventArgs e)
- {
- if (Wizard1.ActiveStepIndex == 1)//当用户进入找回密码第二步
- {
- //如果用户输入的是"admin"则提示用户输入"123456"
- if (txtUserName.Text == "admin")
- {
- lbQuestion.Text = "请输入123456";
- }
- else//如果用户输入的用户名不是"admin"则跳转到第一步
- {
- Wizard1.ActiveStepIndex = 0;
- }
- }
- else if (Wizard1.ActiveStepIndex == 2)//当用户进入找回密码第三步
- {
- if (txtPassword.Text != "123456")
- {
- //用户的找回密码答案正确则修改数据库里的用户登录密码,代码略
- }
- else//如果用户输入的答案不是"123456",则跳转到第二步
- {
- Wizard1.ActiveStepIndex = 1;
- }
- }
- }
- }
这个页面的运行效果如下:
在用户名一栏输入“admin”并点击“下一步”按钮的效果:
在密码提示答案一栏输入“123456”再点击“下一步”按钮:
在新密码和确认新密码中都输入“123456”并点击“完成”按钮。
在上面的例子中没有除了验证控件之外,为了简化流程没有使用任何操作数据库的代码。
MasterPage母板页
在我们做Web应用的时候,经常会遇到一些页面之间有很多相同的显示部分和行为,如果每个页面都去重复编写这些代码,那就是一件非常麻烦的事情。因此在asp.net2.0中提出了母板页的概念,我们可以把多个页面之间相同的行为和显示部分放到母板页中,只需要为每个页面编写不同的部分即可,这样如果我们对公共部分需要变化仅仅更改母板页就能达到目的。母板页的文件后缀名为.master,一个网站中允许定义多个母板页。
母板页不能单独呈现,也就是我们不能在浏览器中直接输入母板页的url地址进行访问,必须依赖于内容页才能呈现。
下面是新建一个母板页的源代码:
- <%@ Master Language="C#" AutoEventWireup="true" CodeFile="FrontPage.master.cs" Inherits="FrontPage" %>
- <!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>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
- </asp:contentplaceholder>
- </div>
- </form>
- </body>
- </html>
在母板页中有一个“<asp:contentplaceholder></asp:contentplaceholder>”标记,这相当于一个占位标记,将来使用了这个母板页的内容页中的内容将在这个标记中显示。因为母板页已经包含了<html><head></head><form runat=”server”></form></html>标记,所以内容页中不允许再出现这些标记。
新建一个使用使用当前使用母板页的内容页步骤如下:
(1)在网站项目或者网站项目下的文件夹上点鼠标右键,在出现的右键菜单中选择“添加新项”,出现如下界面:
注意:一定要勾选“选择母板页”选项。
(2)点击“添加”按钮,这时会出现选择母板页的界面,如下图:
(3)选择正确的母板页,然后点“确定”按钮,这样就完成了添加一个内容页。
这时内容页的代码如下:
- <%@ Page Language="C#" MasterPageFile="~/FrontPage.master" AutoEventWireup="true" CodeFile="MyPage.aspx.cs" Inherits="MyPage" Title="Untitled Page" %>
- <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
- </asp:Content>
在内容页中有一个<asp:Content></asp:Content>标记,只有放在这个标记之间的代码将来运行时才会可见。
内容页有几个常见属性如下表所示:
属性名 | 说明 |
Master | 获取当前内容页所使用的母板页(如果有的话) |
MasterPageFile | 内容所使用的母板页文件的位置 |
Title | 内容页的标题 |
下面是一个内容页访问母板页的例子。
母板页的代码:
- <%@ Master Language="C#" AutoEventWireup="true" CodeFile="FrontPage.master.cs" Inherits="FrontPage" %>
- <!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>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <table><tr><td>
- 服务器时间:<asp:Label ID="lbServerTime" runat="server" Text=""></asp:Label></td></tr>
- <tr><td>
- <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
- </asp:contentplaceholder>
- </td></tr>
- <tr><td>
- 版本号:<asp:Label ID="lbCopyRight" runat="server" Text=""></asp:Label></td></tr>
- </table>
- </div>
- </form>
- </body>
- </html>
内容页的前台代码:
- <%@ Page Language="C#" MasterPageFile="~/FrontPage.master" AutoEventWireup="true" CodeFile="MyPage.aspx.cs" Inherits="MyPage" Title="内容页访问母板页控件的例子" %>
- <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
- 内容页的内容放在这里
- </asp:Content>
内容页的后台代码:
- 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 MyPage : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- //其中lbServerTime是母板页上的控件的ID
- Label lbTimer =(Label)(this.Master.FindControl("lbServerTime"));
- lbTimer.Text = DateTime.Now.ToString("yyyy-MM-dd");
- Label lbCopyRight = (Label)(this.Master.FindControl("lbCopyRight"));
- lbCopyRight.Text = "Version 1.0";
- }
- }
页面的运行效果:
母板页的动态替换
在编程开发中还可以根据条件动态替换内容页所使用的母板页,母板页替换处理要在内容的初始化阶段,也就是在内容页的PreInit事件里。
下面就是一个随即动态替换母板页的例子:
- 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 MyPage : System.Web.UI.Page
- {
- //在这里更换母板页,不能在Page_Load事件里更换,会报异常
- protected override void OnPreInit(EventArgs e)
- {
- if (DateTime.Now.Millisecond % 2 == 0)
- {
- //注意"~/MasterPage.master"母板页中必须有当前母板页中一致的控件
- this.MasterPageFile = "~/MasterPage.master";
- }
- base.OnInit(e);
- }
- }
总结:本篇讲述了一些比较复杂的网页效果的实现办法,比如类似于WinForm中的选项卡式效果、树形菜单、用于多步骤收集用户信息的向导效果等,还有便于网站统一布局合显示的母板页的使用,并且讲述了如何动态替换母板页。下一篇将讲述web.config的用法和配置。
后记:最近有不少朋友在我的博客http://blog.csdn.net/zhoufoxcn上留言,要求在我原有计划上增加一些新的内容,我会酌情增加一些,但是由于时间不会一一照顾到,敬请谅解。
2008-11-01 01:25完成,2008-11-03 02:30整理
周公(周金桥)
注意,因为个人空间大小和下载速度受限,所以以后不再提供从本人主机上的下载地址,可以到www.verycd.com下载《ASP.NET夜话》的测试版视频教程。地址是:http://www.verycd.com/topics/2730883/
Asp.net夜话系列文章:
- Asp.net夜话之一 :asp.net介绍
- Asp.net夜话之二 :asp.net内置对象
- asp.net夜话之三 :表单和控件
- Asp.net夜话之四 :Visual Studio 2005中容易被忽略的技巧
- asp.net夜话之五 :Page类和回调技术
- asp.net夜话之六 :asp.net基本控件
- asp.net夜话之七 :ADO.NET介绍
- asp.net夜话之八 :数据绑定控件
- asp.net夜话之 九:验证控件
- asp.net夜话之 十:复合控件和母板页
- asp.net夜话之十 一:web.config详解