数据绑定(数据绑定表达式 和 自定义表达式构造器)
数据绑定是把数据源和控件相关联并由控件负责自动显示数据的一种特性。数据绑定的关键特征是它是声明性的而不是编程性的,这样做的好处是清晰的分离网页中的控件和代码。
单值绑定
支持单值绑定的控件允许使用数据绑定表达式绑定它们的部分属性。表达式在页面的 .aspx 标记部分输入并由 <%# 表达式 %> 分隔符组成。
<%# EmployeeName %>
它看起来有点像脚本块,但并不是脚本块。如果试图在标签中写入任何代码,将会得到一个错误。这里唯一可做的就是加入有效的数据绑定表达式。
为了计算这样的表达式,必须调用 Page.DataBind()方法。
ASP.NET 会检查页面上所有的表达式并用适当的值去替换它们。
单值绑定的数据源可以使属性的值、成员变量、函数的返回值,还可以是任何运行时可计算的表达式。
<%# Request.Browser.Browser %>
<%# GetUserName() %>
<%# 1+(2 * 20) %>
<%# "John" + "Smith" %>
示例:
protected void Page_Load(object sender, EventArgs e)
{
Page.DataBind();
}
protected string FilePath
{
get { return "001.jpg"; }
}
protected string GetFilePath()
{
return "001.jpg";
}
<form id="form1" runat="server">
<asp:Image ID="Image1" runat="server" ImageUrl='<%# "~/images/" + FilePath %>' /><br />
<asp:Label ID="Label1" runat="server" Text="<%# FilePath %>"></asp:Label><br />
<asp:TextBox ID="TextBox1" runat="server" Text="<%# GetFilePath() %>"></asp:TextBox>
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="<%# FilePath %>">HyperLink</asp:HyperLink>
</form>
其他类型的表达式
ASP.NET 包含一个内置的表达式构造器,它用于从 web.config 文件解析自定义应用程序设置并连接字符串信息。
例如,要从 web.config 的 <appSettings> 中获取一个叫做 appName 的应用程序设置:
<asp:Literal ID="Literal1" runat="server" Text="<%$ AppSettings:appName %>" />
$表达式和数据绑定表达书的区别:
- 计算 $表达式 不需要执行 Page.DataBind(),它们总是在页面呈现时自动计算
- $表达式 不可以在页面上随意放置。必须放在控件标签内,也就是说如果希望像使用普通文本一样使用 $表达式 ,也必须把它们内嵌到 Literal 控件中。(Literal 控件把它的文本以完全未格式化的 HTML 形式输出。
$表达式的第一部分指定了表达式构造器的名称。例如,AppSettings:appName 可以工作是因为 AppSettingsExpressionBuilder 被注册用于处理所有以 AppSettings 开头的表达式。类似的,ResourceExpressionBuilder 用于插入资源,ConnectionStringsExpressionBuilder 用于从 <connectionStrings> 节读取连接字符串信息。
<asp:Literal ID="Literal1" runat="server" Text="<%$ AppSettings:appName %>" />
<asp:Literal ID="Literal2" runat="server" Text="<%$ ConnectionStrings:Northwind %>" />
从技术角度讲,$表达式不包括数据绑定,但它们以相同的方式工作具有相似的语法。
自定义表达式构造器
开发需要嵌入到多个 Web 应用程序的独立应用程序时,自定义$表达式最为有用。
假设,你创建了一个可以插入随机数的自定义表达式构造器,你希望可以这样写标签以显示 1 到 6 之间的随机数:
<asp:Literal runat="server" Text="<%$ RandomNumber:1,6 %>" />
遗憾的是,创建自定义表达式构造器不会像想象中那么简单,问题在于代码是如何编译的。编译包含表达式的页面时,计算代码的表达式也必须同时编译。但是,这时候你并不希望表达式现在就被计算,而是希望每次请求页面时表达式被重新计算。为了达到这一目的,表达式构造器需要生成一段完成相应任务的通用代码。
使这些成为可能的技术是 CodeCom(代码文档对象模型)---- 动态生成代码构造的模型。每个表达式构造器包含一个使用 CodeCom 生成表达式所需代码的 GetCodeExpression()方法。也就是说,要创建 RandomNumberExpressionBuilder,就需要创建 GetCodeExpression()方法,它使用 CodeCom 生成计算随机数所需的代码片段。很显然,这并不是那么简单。
所有的表达式构造器都必须从 ExpressionBuilder 基类(在 System.Web.Compilation 命名空间中)继承。
这是可能的声明:
public class RandomNumberExpressionBuilder:ExpressionBuilder
{ …… }
导入以下命名空间以使代码更简洁:
using System.Web.Compilation;
using System.CodeDom;
using System.ComponentModel;
创建一个表达式构造器的简便方法时先创建一个执行所需任务的静态方法,这样的好处是使用 CodeDom 时,只要生成一行代码就可以调用 GetRandomNumber()方法(不再需要产生随机数的代码):
public static string GetRandomNumber(int lowerLimit, int upperLimit)
{
Random rand = new Random();
int randValue = rand.Next(lowerLimit, upperLimit + 1);
return randValue.ToString();
}
现在需要重写 GetCodeExpression()方法,该方法由 ASP.NET 发现表达式和表达式构造器匹配的时候调用(编译页面时)。在这个方法中,你需要检查表达式是否有错,然后生成计算表达式的代码。生成的代码需要用一种与语言无关的方式来实现,需要使用 System.CodeDom.CodeExpression 对象。动态生成的代码会在每次请求页面时执行。
using System;
using System.Web.Compilation;
using System.CodeDom;
using System.Web.UI;
/// <summary>
///RandomNumberExpressionBuilder 的摘要说明
/// </summary>
public class RandomNumberExpressionBuilder : ExpressionBuilder
{
public static string GetRandomNumber(int lowerLimit, int upperLimit)
{
Random rand = new Random();
int randValue = rand.Next(lowerLimit, upperLimit + 1);
return randValue.ToString();
}
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
if (!entry.Expression.Contains(","))
{
throw new ArgumentException("Must include two numbers separated by a comma.");
}
else
{
string[] numbers = entry.Expression.Split(',');
if (numbers.Length != 2)
{
throw new ArgumentException("Only include two numbers.");
}
else
{
int lowerLimit, upperLimit;
if (Int32.TryParse(numbers[0], out lowerLimit) && Int32.TryParse(numbers[1], out upperLimit))
{
// 目前为止,所有的操作都是由常规代码完成的
// 因为表达式中指定的两个数值在每次请求页面时不需要改变。
// 但是随机数每次都需要重新计算,因此必须用 CodeDom 创建一段动态的代码来执行
// 基本的做法就是创建一个调用 GetRandomNumber()静态方法的 CodeExpression
// 首先要得到包含 GetRandomNumber()方法的类的引用
// 这里的示例简化了这个过程,随机数方法就在本类中
CodeTypeReferenceExpression typeRef = new CodeTypeReferenceExpression(this.GetType());
// 代码定义需要传给 GetRandomNumber() 的参数
CodeExpression[] methodParameters = new CodeExpression[2];
methodParameters[0] = new CodePrimitiveExpression(lowerLimit);
methodParameters[1] = new CodePrimitiveExpression(upperLimit);
// 现在可以创建调用 GetRandomNumber() 方法的 CodeExpression
// 可以通过创建 CodeMethodInvokeExpression 类的实例来完成
// CodeMethodInvokeExpression 类继承自 CodeExpression 类
return new CodeMethodInvokeExpression(typeRef, "GetRandomNumber", methodParameters);
}
else
{
throw new ArgumentException("Use valid integers.");
}
}
}
}
}
最后,为了可以使用这个表达式构造器,必须在 web.config 中配置:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0">
<expressionBuilders>
<add expressionPrefix="RandomNumber" type="RandomNumberExpressionBuilder"/>
</expressionBuilders>
</compilation>
</system.web>
。。。。。。
</configuration>
现在,可以在 Web 表单的标记中这样使用表达式构造器了:
<asp:Literal runat="server" Text="<%$ RandomNumber:1,100 %>" />
表达式构造器可能的应用很吸引人,尤其是在多个 Web 应用程序应用中。因为如果你仅仅是在单个 Web 应用中,那还是使用数据绑定表达式来的更为简单些,比如:
<%# GetRandomNumber(1,100)%>
再在页面后台代码创建:
protected static string GetRandomNumber(int lowerLimit, int upperLimit)
最后,要调用:
Page.DataBind()