您的位置:首页 > 编程语言 > ASP

ASP.NET 3.5核心编程学习笔记(18):数据绑定表达式

2011-04-18 16:23 671 查看
简单数据绑定

  数据绑定表达式是由<%...%>包裹的可执行代码,以#号为前缀。它可以通过DataBoundLiteralControl类的实例以编程方式加以管理。

  数据绑定表达式通常从数据源获取数据,但并不是说它一定要从数据源获取数据,只要返回绑定的数据,任何可执行代码都是可以接受的。它仅在控件的DataBinding事件被触发时才执行计算。

  示例:<asp:label runat="server" Text='<%# DataTime.Now %>' />

  如果要对表达式用引号,应选择单引号。

  我们在页面中定义的数据绑定表达式会在DataBind被调用后计算。我们可以调用页面对象的DataBind方法,也可以调用指定控件上的。如果调用页面对象上的,便以递归方式调用定义在该页面所有控件的DataBind方法,如果不调用DataBind,<%#...%>永远不会被计算。

  数据绑定表达式非常适合基于页面中的其他控件更新当前控件的属性,且完全以声明方式编写。

<asp:DropDownList ID="SelColors" runat="server" AutoPostBack="True">
<asp:ListItem>Orange</asp:ListItem>
<asp:ListItem>Green</asp:ListItem>
<asp:ListItem>Red</asp:ListItem>
<asp:ListItem>Blue</asp:ListItem>
</asp:DropDownList>
<asp:Label runat="server" ID="lblColor" Text='<%# "<b>You Selected:</b>" + SelColors.SelectedValue %>' />


  注意:<%#...%>中的表达式可以为方法、常量、属性的结合体,只要最后的结果匹配绑定属性的类型即可。表达式的计算需要回发,并调用DataBind方法。为此,我们将AutoPostBack设为true,同时还需要调用页面或标签的DataBind方法来触发刷新过程。

protected void Page_Load(object sender, EventArgs e)
{
DataBind();
}


  考虑下面的代码:

ForeColor='<%# "orange" %>'
ForeColor="orange"


  以上代码只有第二条语句能被正常解析。原因是,数据绑定表达式需要确保其返回值的类型与控件属性的类型相匹配。但使用纯文本常量字符串没有问题,因为页面解析器会识别该表达式。如果需要解析器会插入适当的类型转换代码。

数据绑定表达式的内部实现

  如果Web页面中出现数据绑定表达式会发生什么情况呢?考虑下面的代码:

  <asp:label runat="server" id="today" text='<%# DateTime.Now %>' />


  在页面解析器处理.aspx源代码时,会为每个服务器控件生成一个工厂方法,该工厂方法所做的工作只是将标签的名称映射到一个服务器控件的类,并以赋值方式将标签中的属性(attribute)转换为对象的属性(property)。此外,如果有数据绑定表达式,解析器还会添加当前控件的DataBinding事件的处理程序。以下代码为该过程的执行结果:

private Control __BuildControlToday()
{
Label __ctrl = new Label();
this.today = __ctrl;
__ctrl.ID = "today";

__ctrl.DataBinding += new EventHandler(this.__DataBindToday);
return __ctrl;
}


  该处理程序将数据绑定表达式的内容分步赋给相应属性:

public void __DataBindToday(object sender, EventArgs e)
{
Label target;
target = (Label)sender;
target.Text = Convert.ToString(DataTime.Now);
}


  如果数据绑定表达式的值与期望的类型不匹配,则会出现编译错误。如果期望的类型为字符串,解析器便会通过Convert.ToString方法执行标准的转换。

DataBinder类

  Eval方法是一种运算符,专用于数据绑定表达式,用于访问绑定数据项的公共属性。ASP.NET 2.0之前的页面类中没有Eval方法,如果在ASP.NET 1.x应用程序中直接使用,则会产生编译错误。对于所有版本的ASP.NET来说,我们可以使用一个功能相同的方法,其名称也为Eval,但来自另一个类--DataBinder。

  通过Eval方法,我们能够访问绑定数据项的公共属性。但需要澄清,这个上下文中的公共属性是指什么?实现IEnumerable的类都可以绑定到控件上。具体的类包括DataTable(每个数据项在逻辑上对应一条记录),也包括自定义集合(每个数据项对应于给定类的实例)。Eval方法会针对数据项的属性集来查询数据项对象。代表记录的对象会返回所有字段的描述,而其他对象会返回各自的公共属性集。

  DataBinder类支持数据绑定表达式的生成和解析,其中的静态方法Eval十分重要。对于运行时的对象,该方法会使用反射来解析并计算表达式。该方法的一般语法为:

  <%# DataBinder.Eval(Container.DataItem, expression) %>


  Container.DataItem表达式用于引用一个对象,该对象中的表达式会被计算。expression一般为数据项对象中要访问字段的名称。它可以为包括索引或属性名的表达式。DataItem属性代表当前容器上下文中的对象。通常,容器一般为项目对象的当前实例。

更简洁的Eval

  原始的DataBinder.Eval语法在ASP.NET 2.0和更高版本中被简化了,代码可以这样写:

<%# Eval(expression) %>


  而ASP.NET 1.x只能接受下述表达式:

<%# DataBinder.Eval(Container.DataItem, expression) %>


  显然,ASP.NET 2.0及更高版本也完全支持DataBinder类。

  <%# ... %>分割符中出现的所有代码都会被ASP.NET运行特殊处理。当页面被编译后,对Eval方法的调用会被插入到页面的源代码中,并单独存在。下面的代码揭示了其内部细节:

object o = Eval("lastname");
string result = Convert.ToString(o);


  调用的结果会被转换为字符串,并赋给数据绑定控件,随后,数据绑定文本会被插入到页面控件树中。

  有了Eval方法,TemplateControl类得到了扩展,下面的伪码揭示了该方法的内部原理:

protected object Eval(string expression)
{
if(Page == null)
throw new InvalidOperationException(...);
return DataBinder.Eval(Page.GetDataItem(), expression);
}


  由此可见,Eval方法只是一个封闭器而已,它围绕着DataBinder.Eval方法构建而成。DataBinder.Eval方法由当前容器的数据项调用。当前容器的数据在数据绑定操作执行之前是空的,这是Eval与DataBinder.Eval间的主要差异。

  TemplateControl的Eval是一种数据绑定方法,仅用于数据绑定控件上下文中数据绑定操作期间。而DataBinder.Eval是一个完全自由的方法,可在任意位置使用。

默认数据项的获取

  在前面演示页面Eval方法的代码中用到了Page类的GetDataItem方法。这是什么呢?如前所述,简化的语法用到了一个默认的Container.DataItem上下文对象。GetDataItem正是返回该对象的函数。

  确切地讲,GetDataItem是基于栈的调用机制的终点(这种机制会跟踪页面当前的绑定上下文)。控件树中的每个控件会在各自的DataBind方法被调用时压入这个栈。DataBind方法返回时,相应控件会从栈中弹出。如果该栈为空,且试图以编程方式调用Eval,GetDataItem会抛出无效操作异常。总而言这,Eval的快捷方式只能在模板中使用,如果需要在其他位置访问数据项属性,必须借助于DataBinder.Eval,并显式地指示数据项对象。

Bind方法

  使用Eval方法的地方也可以使用Bind方法,二者的语法类似:

<asp:TextBox Runat="server" ID="TheNotes" Text='<%# Bind("notes") %>' />


  最大的不同在于Bind可以双向执行--读和写。例如,在设置Text属性时,Bind方法的行为与Eval一致。当Text被读取时,Bind会将值存储到集合中。ASP.NET中的数据绑定控件能自动获取这些值,并将它们填充插入或编辑命令的参数列表,并对数据源执行这些命令。传到Bind参数的名称必须与命令中参数的名称匹配。如,上述文本框会为@notes参数提供值。

用户定义的动态表达式

  数据绑定表达式不是真正的动态表达式,它们仅会在数据绑定调用上下文中被计算。

  动态表达式与数据绑定的语法相似,它使用的是$前缀。动态表达式会在页面编译时计算,表达式的内容会被提取,转换为代码,并注入为页面生成的代码中。有几个现有的表达式生成器:



  或要以声明方式将某个控件属性绑定到表达式的值,可使用以下模式:

  <%$ expression %>

  确切的语法取决于每种表达式关联的生成器的定义。但注意,页面主体中不允许出现文本表达式。换言之,我们只能对控件的属性应用表达式,而不能像下面这样使用:

<h1><%$ AppSettings:AppVersionNumber %></h1>


  我们应该将表达式封装在服务器控件中,最简单的是使用Literal控件,代码如下:

<h1><asp:Literal runat="server" Text="<%$ Resource:Resource, AppWelcome %>" /></h1>
<hr/><h1><asp:Literal runat="server" Text="<%$ AppSettings:AppVersionNumber %>" /></h1>
<hr/>


  显然,App_GlobalResource中要包含AppWelcome字符串资源,Web.Config文件中也要有AppVersionNumber设置。

  ConnectionStrings表达式对于数据源控件非常有用,它避免了在aspx文件中对连接字符串硬编码。

  开发者通过编写从ExpressionBuilder派生的类,可以定义其他的表达式。为使其能够识别并被正确处理,需要在web.config文件中注册自定义的表达式生成器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐