c#三层架构

1.三层之间的关系:
三层是指:界面显示层(UI),业务逻辑层(Business),数据操作层(Data Access)
文字描述
Clients对UI进行操作,UI调用Business进行相应的运算和处理,Business通过Data Access对Data Base进行操作。
优点
l          增加了代码的重用。Data Access可在多个项目中公用;Business可在同一项目的不同地方使用(如某个软件B/S和C/S部分可以共用一系列的Business组件)。
l          使得软件的分层更加明晰,便于开发和维护。美工人员可以很方便地设计UI设计,并在其中调用Business给出的接口,而程序开发人员则可以专注的进行代码的编写和功能的实现。
2.Data Access的具体实现:
DataAgent类型中变量和方法的说明:
private string m_strConnectionString; //连接字符串
private OleDbConnection m_objConnection; //数据库连接
public DataAgent(string strConnection) //构造方法,传入的参数为连接字符串
private void OpenDataBase() //打开数据库连接
private void #region CloseDataBase() //关闭数据库连接
public DataView GetDataView(string strSqlStat) //根据传入的连接字符串返回DataView
具体实现代码如下:
public  class DataAgent
{
    private string m_strConnectionString;
   private OleDbConnection m_objConnection;
    #region  DataAgend
    ///<summary>
    /// Initial Function
    ///</summary>
    ///<param name="strConnection"></param>
    public DataAgent(string strConnection)
    {
        this.m_strConnectionString = strConnection;
    }
    #endregion
 
    #region  OpenDataBase
    ///<summary>
    /// Open Database
    ///</summary>
    private void OpenDataBase()
    {
        try
        {
            this.m_objConnection = new OleDbConnection();
            this.m_objConnection.ConnectionString = this.m_strConnectionString;
            if (this.m_objConnection.State != ConnectionState.Open)
            {
                this.m_objConnection.Open();
            }
        }
        catch (Exception e)
        {
            throw e;
        }
    }
    #endregion
 
    #region  CloseDataBase
    ///<summary>
    /// Close Database
    ///</summary>
    private void CloseDataBase()
    {
        if (this.m_objConnection != null)
        {
            if (this.m_objConnection.State == ConnectionState.Open)
            {
                this.m_objConnection.Close();
            }
        }
    }
    #endregion
 
    #region  GetDataView
    ///<summary>
    /// Execute the sql and return the default table view
    ///</summary>
    ///<param name="strSelectString">Select String</param>
    ///<returns>DataView of the DataTable</returns>
    public DataView GetDataView(string strSqlStat)
    {
        try
        {
            this.OpenDataBase();
            OleDbDataAdapter objDataAdapter = new OleDbDataAdapter(strSqlStat.Trim(), this.m_objConnection);
            DataSet objDataSet = new DataSet();
            objDataAdapter.Fill(objDataSet);
            return objDataSet.Tables[0].DefaultView;
        }
        catch (Exception e)
        {
            throw e;
        }
        finally
        {
            this.CloseDataBase();
        }
    }
    #endregion
}
3.Business的具体实现:
建立名为Base的类,此类作为其他事务类的基类,其中定义了一个DataAgent的实例。其他所有的Business类都从该改类派生。
在该类中添加对DataAgent的引用,使所有的事务类都能使用DataAgent中的方法。
Base.cs源代码:
public  abstract class Base
{
    protected DataAgent OleDBAgent = new DataAgent("Provider=SQLOLEDB;Data Source=(local);DataBase=test;User ID=sa;PWD=");
}
准备好了数据操作层和事务层的基类,底下就可以正式地开始业务逻辑类的开发了,如有一个显示新闻的类News,其中包含了一个GetNewsList()的方法,该方法用来获取所有的新闻标题列表,代码如下:
public  class News : Base
{
    public DataView GetNewsList()
    {
        string strSql;
        strSql = "";
         strSql += " SELECT Top 10 NewsId,NewsTitle ";
        strSql += " FROM Tb_News";
        strSql += " WHERE NewsEnable = 1";
        strSql += " ORDER BY NewsId ";
        return OleDBAgent.GetDataView(strSql);
    }
}
由于数据库结构比较简单,在此就不再给出详细的表结构。
4.UI层对Business中接口的调用
首先,在窗体Form1中添加对News类的引用。
然后,在窗体Form1中添加一个(DataGridView)dgNews用来显示新闻列表。
在窗体的 Form1_Load方法中添加如下代码:
private  void Form1_Load(object sender, EventArgs e)
{
    News objNews = new News();
    this.dgNews.DataSource = objNews.GetNewsList();
}
 
实例:
复制代码
 /// <summary>
        /// 初始化登录名称、登录密码(Model类)
        /// </summary>
        private string adminUser = string.Empty; //设置用户名称为空值
        private string adminPwd = string.Empty; //设置用户密码为空值
        public string AdminUser
        {
            get
            {
                return this.adminUser;
            }
            set
            {
                this.adminUser = value;
            }
        }
        public string AdminPwd
        {
            get
            {
                return this.adminPwd;
            }
            set
            {
                this.adminPwd = value;
            }
        }
复制代码

 

复制代码
 /// <summary>
        /// 用户登录(BLL类)
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public static int sysLogin(Model m)
        {
            string str = "adminValid"; //存储过程名称
            SqlParameter[] sqlParameter =
                {
                    //将UI层传递过来的用户名称和密码赋值给存储过程中的变量分别是adminUser和adminPwd(注意大小写)
                    new SqlParameter("adminUser",m.AdminUser),
                    new SqlParameter("adminPwd",m.AdminPwd)
                };
            DAL d = new DAL();
            return Int32.Parse(d.ExecuteScalar(str,sqlParameter));
        }
复制代码

 

复制代码
  /// <summary>
        /// 新建一个SQL登录链接
        /// </summary>
        /// <returns></returns>
        private static SqlConnection con()
        {
            return new SqlConnection("Data Source=localhost;Initial Catalog=数据库名称;Integrated Security=SSPI;");
        }
        /// <summary>
        /// 执行操作(DAL类)
        /// </summary>
        /// <param name="str"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        public string ExecuteScalar(string str, SqlParameter[] sql)
        {
            SqlConnection con = DAL.con();
            try
            {
                con.Open();
                SqlCommand com = new SqlCommand(str, con);
                com.CommandType = CommandType.StoredProcedure;
                com.Parameters.AddRange(sql);
                return Convert.ToString(com.ExecuteScalar()); //返回受影响的行数(例如影响的行数为1,那么返回数值1到BLL层,然后BLL层将数值1返回到UI层)
            }
            catch (Exception Error)
            {
                throw Error;
            }
            finally
            {
                con.Close();
            }
        }
复制代码

 

复制代码
//UI层
        Model m = new Model(); //实例化Model类
        m.AdminUser = this.TextBox1.Text.ToString(); //将文本框1中的值传递给Model类中的AdminUser
        m.AdminPwd = this.TextBox2.Text.ToString(); //将文本框2中的值传递给Model类中的AdminPwd
        if (BLL.sysLogin(m) > 0)
        {
            this.Label1.Text = "登录成功!马上进入管理平台...";
        }
        else
        {
            this.Label1.Text = "用户或密码错误,请重新输入!";
        }
复制代码
复制代码
--存储过程(SQL2005)
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

ALTER PROC [dbo].[adminValid]
@adminUser varchar(20),@adminPwd varchar(120)
AS
SELECT COUNT(*) FROM admin WHERE adminUser = @adminUser AND adminPwd = @adminPwd
复制代码

 

3.

三层架构图[转]

一.三层架构图
c#三层架构_第1张图片
 

二.系统各层次职责
1.UI(User Interface)层的职责是数据的展现和采集,数据采集的结果通常以Entity object提交给BL层处理。Service Interface侧层用于将业务或数据资源发布为服务(如WebServices)。
2.BL(Business Logic)层的职责是按预定的业务逻辑处理UI层提交的请求。
(1)Business Function 子层负责基本业务功能的实现。
(2)Business Flow 子层负责将Business Function子层提供的多个基本业务功能组织成一个完整的业务流。(Transaction只能在Business Flow 子层开启。)
3.ResourceAccess层的职责是提供全面的资源访问功能支持,并向上层屏蔽资源的来源。
(1)BEM(Business Entity Manager)子层采用DataAccess子层和ServiceAccess子层来提供业务需要的基础数据/资源访问能力。
(2)DataAccess子层负责从数据库中存取资源,并向BEM子层屏蔽所有的SQL语句以及数据库类型差异。
DB Adapter子层负责屏蔽数据库类型的差异。
ORM子层负责提供对象-关系映射的功能。
Relation子层提供ORM无法完成的基于关系(Relation)的数据访问功能。
(3)ServiceAccess子层用于以SOA的方式从外部系统获取资源。
注: Service Entrance用于简化对Service的访问,它相当于Service的代理,客户直接使用Service Entrance就可以访问系统发布的服务。Service     Entrance为特定的平台(如Java、.Net)提供强类型的接口,内部可能隐藏了复杂的参数类型转换。
(4)ConfigAccess子层用于从配置文件中获取配置object或将配置object保存倒配置文件。
4.Entity侧层跨越UI/BEM/ResourceManager层,在这些层之间传递数据。Entity侧层中包含三类Entity,如下图所示:
c#三层架构_第2张图片
 
三.Aspect
 Aspect贯穿于系统各层,是系统的横切关注点。通常采用AOP技术来对横切关注点进行建模和实现。
1.Securtiy Aspect:用于对整个系统的Security提供支持。
2.ErrorHandling Aspect:整个系统采用一致的错误/异常处理方式。
3.Log Aspect:用于系统异常、日志记录、业务操作记录等。

四.规则
1.系统各层次及层内部子层次之间都不得跨层调用。
2.Entity object 在各个层之间传递数据。
3.需要在UI层绑定到列表的数据采用基于关系的DataSet传递,除此之外,应该使用Entity object传递数据。
4.对于每一个数据库表(Table)都有一个DB Entity class与之对应,针对每一个Entity class都会有一个BEM Class与之对应。
5.有些跨数据库或跨表的操作(如复杂的联合查询)也需要由相应的BEM Class来提供支持。
6.对于相对简单的系统,可以考虑将Business Function子层和Business Flow 子层合并为一个。
7.UI层和BL层禁止出现任何SQL语句。

五.错误与异常
        异常可以分为系统异常(如网络突然断开)和业务异常(如用户的输入值超出最大范围),业务异常必须被转化为业务执行的结果。
1.DataAccess层不得向上层隐藏任何异常(该层抛出的异常几乎都是系统异常)。
2.要明确区分业务执行的结果和系统异常。比如验证用户的合法性,如果对应的用户ID不存在,不应该抛出异常,而是返回(或通过out参数)一个表示验证结果的枚举值,这属于业务执行的结果。但是,如果在从数据库中提取用户信息时,数据库连接突然断开,则应该抛出系统异常。
3.在有些情况下,BL层应根据业务的需要捕获某些系统异常,并将其转化为业务执行的结果。比如,某个业务要求试探指定的数据库是否可连接,这时BL就需要将数据库连接失败的系统异常转换为业务执行的结果。
4.UI层(包括Service层)除了从调用BL层的API获取的返回值来查看业务的执行结果外,还需要截获所有的系统异常,并将其解释为友好的错误信息呈现给用户。

六.项目组织目结构
 以BAS系统为例。
1.主目录结构:
 c#三层架构_第3张图片
2.命名空间命名:每个dll的根命名空间即是该dll的名字,如EAS.BL.dll的根命名空间就是EAS.BL。每个根命名空间下面可以根据需求的分类而增加子命名空间,比如,EAS.BL的子空间EAS.BL.Order与EAS.BL.Permission分别处理不同的业务逻辑。
3.包含众多子项目的庞大项目的物理组织:
 c#三层架构_第4张图片
核心子项目Core的位置:
c#三层架构_第5张图片
 
Core子项目中包含一些公共的基础设施,如错误处理、权限控制方面等。

七.发布服务与服务回调
以EAS系统为例。
 c#三层架构_第6张图片
1.同UI层的Page一样,服务也不允许抛出任何异常,而是应该以返回错误码(int型,1表示成功,其它值表示失败)的形式来表明服务调用出现了错误,如果方法有返回值,则返回值以out参数提供。
2. 如果BAS系统提供了WebService(Remoting)服务,则BAS必须提供BAS.Entrance.dll。 BAS.Entrance.dll封装了与BAS服务交换信息的通信机制,客户系统只要通过BAS.Entrance.dll就可以非常简便地访问BAS 提供的服务。
3.如果BAS需要通过WebService(Remoting)回调客户系统,则必须提供仅仅定义了接口的BAS.CallBack.dll,客户系统将引用该dll,实现其中的接口,并将其发布为服务,供BAS回调。
4.当WebService的参数或返回值需要是复杂类型――即架构图中的Service Entity,则Service Entity应该在对应的BAS.EntranceParaDef.dll或BAS.CallBackParaDef.dll中定义。 WebService定义的方法中的复杂类型应该使用Xml字符串代替(注意,Entrance和CallBack接口对应服务的方法的参数是强类型的),而Xml字符串和复杂类型对象之间的转换应当在BAS.Entrance.dll或BAS.CallBack.dll中实现。

 

4.MasterPageFile:

母版MasterPage.master文件 的应用

虽然母版页和内容页功能强大,但是其创建和应用过程并不复杂。本节和下一节将以创建如图1所示示例为例,向读者详细介绍,使用Visual Stuido 2005创建母版页和内容页的方法以及相关知识。本节的重点是创建母版页的方法。

母版页中包含的是页面公共部分,即网页模板。因此,在创建示例之前,必须判断哪些内容是页面公共部分,这就需要从分析页面结构开始。图1所示显示的是一 个页面截图。在下文中,暂称该页面名为Index.aspx,并且假设其为某网站中的一页。通过分析可知,该页面的结构如图5所示。 
c#三层架构_第7张图片
图5 页面结构图 

   页面Index.aspx由4个部分组成:页头、页尾、内容1和内容2。其中页头和页尾是Index.aspx所在网站中页面的公共部分,网站中许多页 面都包含相同的页头和页尾。内容1和内容2是页面的非公共部分,是Index.aspx页面所独有的。结合母版页和内容页的有关知识可知,如果使用母版页 和内容页来创建页面Index.aspx,那么必须创建一个母版页MasterPage.master和一个内容页Index.aspx。其中母版页包含 页头和页尾等内容,内容页中则包含内容1和内容2。 

   这个专题中主要讲解的是MasterPage,给刚刚建立的工程添加一个MasterPage: 

c#三层架构_第8张图片

MasterPage以master为后缀名,我们刚刚建立了一个MasterPage.master文件,该文件有如下内容:

复制代码
 1 <%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
 2  
 3   
 4  
 5  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 6  
 7   
 8  
 9  <html xmlns="http://www.w3.org/1999/xhtml" >
10  
11  <head runat="server">
12  
13      <title>Untitled Page</title>
14  
15  </head>
16  
17  <body>
18  
19      <form id="form1" runat="server">
20  
21      <div>
22  
23          <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
24  
25          </asp:contentplaceholder>
26  
27      </div>
28  
29      </form>
30  
31  </body>
32  
33  </html>
34 
复制代码

粗看还以为这是一个普通的 aspx页面,其实不是,最上面的<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %> 

表面明这是一个master文件,同时在页面中你可以看到用<div>包裹着的一个asp控件

Contentplaceholder,这个叫“内容占位符”,他的作用就是先通过div或者table进行分割,然后“霸占”一个地方,声明此地有“主”了,不过主人不是Contentplaceholder,而是后面会说道到的Content控件。

注意:<div>一般通过css样式表来控制页面的布局,如cnblogs里面的很多皮肤都是如此,为了不把问题复杂化,我还是用table。在Design状态下画出如下表格(vs.net 2005 的Design功能真的好用很多^_^): 



c#三层架构_第9张图片

这是一个很标准的网页页面布局,下一步就把Contentplaceholder放进去“占地盘”“: 

c#三层架构_第10张图片

放完后我们把各个部分的ContentPlaceHolder重新命名一次,更改后的代码如下:

复制代码
1 <%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
 2  
 3   
 4  
 5  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 6  
 7   
 8  
 9  <html xmlns="http://www.w3.org/1999/xhtml" >
10  
11  <head runat="server">
12  
13      <title>Untitled Page</title>
14  
15  </head>
16  
17  <body>
18  
19      <form id="form1" runat="server">
20  
21     <table width="60%">
22  
23              <tr>
24  
25                  <td colspan="3" height="80">
26  
27                      <asp:ContentPlaceHolder ID="TopContent" runat="server">
28  
29                      </asp:ContentPlaceHolder>
30  
31                  </td>
32  
33              </tr>
34  
35              <tr>
36  
37                  <td height="300" width="25%">
38  
39                      <asp:ContentPlaceHolder ID="LeftContent" runat="server">
40  
41                      </asp:ContentPlaceHolder>
42  
43                  </td>
44  
45                  <td>
46  
47                      <asp:ContentPlaceHolder ID="CenterContent" runat="server">
48  
49                      </asp:ContentPlaceHolder>
50  
51                  </td>
52  
53                  <td width="25%">
54  
55                      <asp:ContentPlaceHolder ID="RightContent" runat="server">
56  
57                      </asp:ContentPlaceHolder>
58  
59                  </td>
60  
61              </tr>
62  
63              <tr>
64  
65                  <td colspan="3" style="height: 80px">
66  
67                      <asp:ContentPlaceHolder ID="CopyrightContent" runat="server">
68  
69                      </asp:ContentPlaceHolder>
70  
71                  </td>
72  
73              </tr>
74  
75          </table>
76  
77      </form>
78  
79  </body>
80  
81  </html>
82 
复制代码

在Design状态下我们可以看到如下效果: 
c#三层架构_第11张图片

有了MasterPage后我们该如何使用?光上面所说的根本解决不了任何问题。下面看看如何使用:

首先建立一个新的aspx页面,记得把Select Master Page项选上: 

c#三层架构_第12张图片

此时点击Add后会谈出下面这个窗口: 

c#三层架构_第13张图片

由于目前只有一个MasterPage文件,所以只能选择它,确定后新的Default2.aspx页面被建立,这个时候你会发现Default2.aspx页面中没有标准的html页面的格式,取而代之的是asp.net控件Content,Default2.aspx中的代码如下:

复制代码
1 <%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" Title="Untitled Page" %>
 2  
 3  <asp:Content ID="Content1" ContentPlaceHolderID="TopContent" Runat="Server">
 4  
 5  </asp:Content>
 6  
 7  <asp:Content ID="Content2" ContentPlaceHolderID="LeftContent" Runat="Server">
 8  
 9  </asp:Content>
10  
11  <asp:Content ID="Content3" ContentPlaceHolderID="CenterContent" Runat="Server">
12  
13  </asp:Content>
14  
15  <asp:Content ID="Content4" ContentPlaceHolderID="RightContent" Runat="Server">
16  
17  </asp:Content>
18  
19  <asp:Content ID="Content5" ContentPlaceHolderID="CopyrightContent" Runat="Server">
20  
21  </asp:Content>
复制代码

注意观察一下,在<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" Title="Untitled Page" %>里多了一个MasterPageFile="~/MasterPage.master"项,这表明这个页面使用MasterPage.master

,该文件存放在与该页面相同的目录下(当有多个MasterPage文件时你也可以新建立一个目录方便管理)。记得刚才在MasterPage.master中的设置吗,我们定义了五个ContentPlaceHolder,ID分别是TopContent,LeftContent,CenterContent,RightContent,CopyrightContent,在Default2.aspx页面下的Content控件里,有一个属性就是ContentPlaceHolderID,该字段表明该Content控件中的内容代替ID指向的ContentPlaceHolder占位控件,这就是真的“霸主”了。这样一来,页面布局就使用MasterPage.master中的,而内容就使用Default2.aspx中Content控件下的,因此你在Default2.aspx 中找不到Html页面的基本格式标记,如<head>、<body>。看一下Design下Default2.aspx会是什么样子: 

c#三层架构_第14张图片

和MasterPage.master很像,但又不同,因为除了Content控件占用的地方是可以编辑的外其他地方都是不可以编辑的。

 

现在可以总结MasterPage的作用了,MasterPage其实是一种模板,它可以让你快速的建立相同页面布局而内部不同的网页,如果一个网站有多个MasterPage,那么新建aspx文件的时候就可以选择需要实现页面布局的MasterPage。另外,在你没有使用MasterPage之前,如果N个相同的页面布局需要改动成另外一个样式,那么你就要做很多无聊而又不得不做的工作,对N个页面进行一一更改,如果使用了MasterPage,你只要改动一个页面也就是MasterPage文件就可以了。还有,你是否发现你要要部署的web程序越来越大,使用MasterPage在一定程度上会减小web程序的大小,因为所有的重复的html标记都只有一个版本。 

在PS4.0中的应用.

c#三层架构_第15张图片

如图所示:在在PS4.0中所使用的MasterPage.master.图中所显示的是content控件 

c#三层架构_第16张图片

在SignIn.aspx中的应用.

代码如下:

<%@ Page AutoEventWireup="true" Language="C#" MasterPageFile="~/MasterPage.master"

    Title="Sign In" %>

<asp:Content ID="cntPage" runat="Server" ContentPlaceHolderID="cphPage"> 

c#三层架构_第17张图片

在NewUser.aspx中的使用

代码如下:

<%@ Page AutoEventWireup="true" Language="C#" MasterPageFile="~/MasterPage.master" Title="New User" %>

<asp:Content ID="cntPage" ContentPlaceHolderID="cphPage" Runat="Server" EnableViewState="false">

——————————————————————————————————————
男人的自信来自一个女人对他的崇拜,

女人的高傲来自一个男人对她的倾慕。

5.

复制代码
<table border="1">
        <tr>
                <th>www.dreamdu.com</th>
                <th>.com域名的数量</th>
                <th>.cn域名的数量</th>
                <th>.net域名的数量</th>
        </tr>
        <tr>
                <td>2003年</td>
                <td>1000</td>
                <td colspan="2">2000+3000</td>
        </tr>
        <tr>
                <td>2004年</td>
                <td>4000</td>
                <td>5000</td>
                <td>6000</td>
        </tr>
        <tr>
                <td>2005年</td>
                <td>7000</td>
                <td>8000</td>
                <td>9000</td>
        </tr>
        <tr>
                <td>总数</td>
                <td colspan="3">24000</td>
        </tr>
</table>
复制代码

 

  • colspan属性可以实现单元格跨越多列
  • 内容为"24000"的行跨越了3列,内容为"2000+3000"的行跨越了2列

 5.2  rowspan :  row:行,span:跨度,跨距

6.母版PageMaster.master

母版页中ContentPlaceHolder 控件的作用。

当母版页被一个页面引用时,页面内容与母版页上的ContentPlaceHolder控件合并,生成最终输出。

 ContentPlaceHolder控件的ID 属性与映射到引用页面上一个类似的ID中。当母版页上有不止一个ContentPlaceHolder控件时,这种映射关系是很有用的。

 可以在ContentPlaceHolder 控件外添加任何HTML标记和任何其他控件。告诉他们母版页上的任何服务器端代码都将在所有引用它的页面上执行。

 解释

ContentPlaceHolder控件的作用。每一个页面自身特定的内容将被放置在ContentPlaceHolder控件内。 

 解释内容页的概念。结合下例解释

@Page指令及其属性:

 

 

 

<%@ 

Page 

Language="C#" 

MasterPageFile="~/MasterPages/Master1.master" 

%>  

Language 

属性定义使用的默认语言,而

MasterPageFile 

属性定义使用的母版

文件的路径。

 

解释

Content 

控件用于向内容页添加特定于页面的内容。所有特定于页面

的内容必须放置在

Content 

控件里。

 

引用页面的

 Content 

控件与母版页的对应

ContentPlaceHolder 

控件之间存在

映射关系,这是通过映射它们的

ID

来实现的。

 

 

 

最后,结合以下示例解释母版页的

ContentPlaceHolder 

控件与内容页的

Content

控件之间的关系:

 

 

// Master File: A.Master  

<%@ Master%> 

<asp:ContentPlaceHolder ID= “topContent” runat = “server”>

 

 

//Content File: A.aspx 

<%@Page Master = “A.Master”%>

 

<asp:Content ID = “Content1” ContentPlaceHolderID= “topContent” runat 

= “server”>

 

 

--Some markup-- 

</asp:Content> 

在内容文件(

A.aspx

)的样本代码中,

<%@Page%>

指令的

 master 

属性用于引

用运行时内容文件将使用的母版文件。

 

母版文件(

A.master

)里

 ContentPlaceHolder 

控件的

ID 

属性值与内容文件

A.aspx

)里的

ContentPlaceHolderID 

属性值是一样的。运行时,当浏览器请求

 

A.aspx 

时,那么这两个属性将会被映射,从而合并

Content 

控件的内容与对应的

ContentPlaceHolder 

控件。

 

6.2

关于ContentPlaceHolder与Content控件

定义:

ContentPlaceHolder 控件:在 ASP.NET 母版页中定义内容区域。

Content控件:保存文本、标记和服务器控件以呈现给母版页中的 ContentPlaceHolder 控件。

两者关系:

ContentPlaceHolder 控件在母版页中定义相对内容区域,并呈现在内容页中找到的相关的 Content 控件的所有文本、标记和服务器控件。

Content 控件使用其ContentPlaceHolderID 属性与 ContentPlaceHolder 关联。将 ContentPlaceHolderID 属性设置为母版页中相关的 ContentPlaceHolder 控件的ID属性的值。

通 俗的来讲,ContentPlaceHolder 控件是个容器控件,用来存放内容,但是如果它放在母板页中,那么它的内容页就需要使用Content控件来指定ContentPlaceHolder控件 (好像一个指针一样,通过 ContentPlaceHolderID 属性来指定)来放置内容。

注意:

ContentPlaceHolder控件如果放在母版页中,那么它的内容页是通过Content控件来链接,是可编辑的。

但是Content控件如果放在母板页中,那么它的内容页中没有东西来对其进行链接,是不可编辑的。

举例:

母版页一的代码:

复制代码
1.    <</SPAN>span style="font-size:18px;"><</SPAN>span style="font-size:13px;"><</SPAN>headrunat="server">
2.    <</SPAN>title>演示</</SPAN>title>
3.    <</SPAN>asp:ContentPlaceHolder id="head" runat="server">
4.    </</SPAN>asp:ContentPlaceHolder>
5.    </</SPAN>head>
6.    <</SPAN>body>
7.    <</SPAN>form id="form1" runat="server">母版页演示
8.    <</SPAN>div>
9.    <</SPAN>asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
10.    </</SPAN>asp:ContentPlaceHolder>
11.    </</SPAN>div>
12.    </</SPAN>form>
13.    </</SPAN>body></</SPAN>span>
14.    </</SPAN>span>
复制代码
母版页一的内容页的代码:
1.    <</SPAN>span style="font-size:18px;"><</SPAN>span style="font-size:13px;"><</SPAN>asp:ContentID="Content1" ContentPlaceHolderID="head" Runat="Server">
2.    </</SPAN>asp:Content>
3.    <</SPAN>asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
4.    </</SPAN>asp:Content></</SPAN>span>
5.    </</SPAN>span>

母版页二的代码(二级母版页,继承自母版页一):

1.    <</SPAN>span style="font-size:18px;"><</SPAN>span style="font-size:13px;"><</SPAN>asp:ContentID="Content1" ContentPlaceHolderID="head" Runat="Server">
2.    </</SPAN>asp:Content>
3.    <</SPAN>asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
4.    </</SPAN>asp:Content></</SPAN>span>
5.    </</SPAN>span>

母版页二的内容页的代码:没有代码,是空白。

问题:这样的话二级母版页的内容页就不能进行编辑,如何解决呢?

解决:我们只需在二级母版页中添加ContentPlaceHolder控件即可。

举例:上面的母版页二,我们更改后:

复制代码
1.    <</SPAN>span style="font-size:18px;"><</SPAN>span style="font-size:13px;"><</SPAN>asp:ContentID="Content1" ContentPlaceHolderID="head" Runat="Server">
2.    <</SPAN>asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
3.    </</SPAN>asp:ContentPlaceHolder>
4.    </</SPAN>asp:Content></</SPAN>span>
5.    </</SPAN>span><</SPAN>span style="font-size:13px;"><</SPAN>asp:Content ID="Content2"ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
6.    <</SPAN>asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server">
7.    </</SPAN>asp:ContentPlaceHolder>
8.    </</SPAN>asp:Content>
9.    </</SPAN>span>
复制代码

母版页二的内容页变为:

1.    <</SPAN>span style="font-size:13px;"><</SPAN>asp:Content ID="Content1"ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
2.    </</SPAN>asp:Content>
3.    <</SPAN>asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" Runat="Server">
4.    </</SPAN>asp:Content>
5.    </</SPAN>span> 

 6.3

ContentPlaceHolder、Content 又是什么呢?

这二者是用于母版技术的。

ContentPlaceHolder 用在母版页中,表示这里面的内容可以被 aspx 页中的 Content 内容替换,当然 aspx 页也可以不理会它。

Content 就是用于 aspx 页的,Content 有个属性是 ContentPlaceHolderID,这指明了:母版中对应的 ContentPlaceHolder 那里就放 Content 中的内容。

你可能感兴趣的:(C#)