文章目錄
資料繫結是把資料來源和控制項相關聯並由控制項負責自動顯示資料的一種特性。資料繫結的關鍵特徵是它是聲明性的而不是編程性的,這樣做的好處是清晰的分離網頁中的控制項和代碼。
單值綁定
支援單值綁定的控制項允許使用資料繫結運算式綁定它們的部分屬性。運算式在頁面的 .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()