了解 ASP.NET AJAX UpdatePanel 觸發程序

作者:Scott Cate

在 Visual Studio 的標記編輯器中工作時,您可能會注意到 IntelliSense () UpdatePanel 控制項有兩個子項目。 其中一個是 Triggers 元素,它會指定頁面上的控制項 (或使用者控制項,如果您使用一個) 來觸發元素所在 UpdatePanel 控制項的部分轉譯。

簡介

Microsoft 的 ASP.NET 技術帶來物件導向和事件驅動程式設計模型,並結合編譯器代碼的優點。 不過,其伺服器端處理模型有數個技術固有的缺點,其中許多功能都可以由 Microsoft ASP.NET 3.5 AJAX 延伸模組中包含的新功能來處理。 這些延伸模組可啟用許多新的豐富用戶端功能,包括部分轉譯頁面,而不需要完整頁面重新整理、透過用戶端腳本存取 Web 服務的能力, (包括 ASP.NET 分析 API) ,以及專為鏡像 ASP.NET 伺服器端控制項集中所見的許多控制項配置而設計的廣泛用戶端 API。

本白皮書會檢查 ASP.NET AJAX UpdatePanel 元件的 XML 觸發程式功能。 XML 觸發程式可對可能導致特定 UpdatePanel 控制項部分轉譯的元件提供細微的控制。

本白皮書是以 .NET Framework 3.5 和 Visual Studio 2008 的 Beta 2 版本為基礎。 ASP.NET AJAX Extensions 先前是以 ASP.NET 2.0 為目標的附加元件,現在已整合到 .NET Framework 基類庫。 本白皮書也假設您將使用 Visual Studio 2008,而不是 Visual Web Developer Express,而且會根據 Visual Studio 的使用者介面提供逐步解說, (雖然程式代碼清單完全相容,但不論開發環境) 為何。

觸發程序

根據預設,指定 UpdatePanel 的觸發程式會自動包含任何叫用回傳的子控制項,例如) 已將其 AutoPostBack 屬性設定為 true的 TextBox 控制項 (。 不過,您也可以使用標記以宣告方式包含觸發程式;這會在 <triggers> UpdatePanel 控制項宣告的 區段中完成。 雖然可以透過 Triggers 集合屬性存取觸發程式,但建議您在執行時間 (註冊任何部分轉譯觸發程式,例如,如果在設計階段無法使用控制項, RegisterAsyncPostBackControl(Control)) 使用您頁面的 ScriptManager 物件的 方法,在 Page_Load 事件中。 請記住,頁面是無狀態的,因此您應該在每次建立這些控制項時重新註冊這些控制項。

您也可以停用自動子觸發套裝程式含 (,讓建立回傳的子控制項不會藉由將 ChildrenAsTriggers 屬性設定為 false來自動觸發部分轉譯) 。 這可讓您有最大的彈性來指派哪些特定控制項可能會叫用頁面轉譯,並建議這麼做,讓開發人員加入宣告以回應事件,而不是處理可能發生的任何事件。

請注意,當 UpdatePanel 控制項是巢狀的時,當 UpdateMode 設定為 條件式時,如果觸發了子 UpdatePanel,但父系不是,則只會重新整理子 UpdatePanel。 不過,如果父 UpdatePanel 已重新整理,則子 UpdatePanel 也會重新整理。

<Triggers > 元素

在 Visual Studio 的標記編輯器中工作時,您可能會注意到 IntelliSense 中的 () 控制項有兩個 UpdatePanel 子項目。 最常看到的專案是 <ContentTemplate> 元素,基本上會封裝更新面板所保留的內容, (我們要啟用部分轉譯) 的內容。 另一個元素是 <Triggers> 元素,它會指定頁面上的控制項 (或使用者控制項,如果您使用一個) 來觸發 Triggers > 元素所在 UpdatePanel 控制項 < 的部分轉譯。

元素 <Triggers> 可以包含兩個子節點的任意數目: <asp:AsyncPostBackTrigger><asp:PostBackTrigger> 。 它們都接受兩個屬性和 ControlIDEventName ,而且可以在目前的封裝單位內指定任何 Control (,例如,如果您的 UpdatePanel 控制項位於 Web 使用者控制項內,就不應該嘗試參考使用者控制項所在頁面上的控制項) 。

元素 <asp:AsyncPostBackTrigger> 特別有用,因為它可以將控制項中的任何事件作為封裝單位中 任何 UpdatePanel 控制項的子系,而不只是此觸發程式為子系的 UpdatePanel。 因此,可以進行任何控制項來觸發部分頁面更新。

同樣地, <asp:PostBackTrigger> 元素可以用來觸發部分頁面轉譯,但需要伺服器完整往返的專案。 當控制項通常會觸發部分頁面轉譯 (,例如,當 Button UpdatePanel 控制項的 元素中 <ContentTemplate> 存在控制項時,此觸發程式元素也可以用來強制完整頁面轉譯) 。 同樣地,PostBackTrigger 元素可以指定封裝目前單位中任何 UpdatePanel 控制項子系的任何控制項。

<Triggers > 元素參考

標記子系:

標籤 描述
<asp:AsyncPostBackTrigger> 指定控制項和事件,該控制項和事件會導致包含此觸發程式參考之 UpdatePanel 的部分頁面更新。
<asp:PostBackTrigger> 指定會導致完整頁面更新 (完整頁面重新整理) 的控制項和事件。 當控制項觸發部分轉譯時,這個標記可以用來強制完整重新整理。

逐步解說:跨 UpdatePanel 觸發程式

  1. 使用 ScriptManager 物件集來啟用部分轉譯,建立新的 ASP.NET 網頁。 將兩個 UpdatePanel 新增至此頁面 - 在第一個頁面中,將 Label 控制項 ( Label1 ) 和兩個 Button 控制項 ( Button1 和 Button2 ) 。 Button1 應該說[按一下以更新],而 Button2 應該說 [按一下以更新此問題],或沿著這幾行的某個專案。 在第二個 UpdatePanel 中,只包含 Label 控制項 ( Label2 ) ,但將其 ForeColor 屬性設定為預設值以外的屬性來區分它。
  2. 將兩個 UpdatePanel 標籤的 UpdateMode 屬性設定為 條件式。

清單 1:default.aspx 的標記:



<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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>Untitled Page</title>
   </head>
   <body>
      <form id="form1" runat="server">
         <asp:ScriptManager EnablePartialRendering="true"
            ID="ScriptManager1" runat="server"></asp:ScriptManager>
         <div>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server"
               UpdateMode="Conditional">
               <ContentTemplate>
                  <asp:Label ID="Label1" runat="server" />
                  <br />
                  <asp:Button ID="Button1" runat="server"
                     Text="Update Both Panels" OnClick="Button1_Click" />
                  <asp:Button ID="Button2" runat="server"
                     Text="Update This Panel" OnClick="Button2_Click" />
               </ContentTemplate>
            </asp:UpdatePanel>
            <asp:UpdatePanel ID="UpdatePanel2" runat="server"
               UpdateMode="Conditional">
               <ContentTemplate>
                  <asp:Label ID="Label2" runat="server" ForeColor="red" />
               </ContentTemplate>
               <Triggers>
                  <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
               </Triggers>
            </asp:UpdatePanel>
         </div>
      </form>
   </body>
</html>

  1. 在 Button1 的 Click 事件處理常式中,將 Label1.Text 和 Label2.Text 設定為與時間相關的 (,例如 DateTime.Now.ToLongTimeString () ) 。 針對 Button2 的 Click 事件處理常式,僅將 Label1.Text 設定為時間相依值。

清單 2:在 default.aspx.cs 中修剪程式碼 () :

public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongTimeString();
        Label2.Text = DateTime.Now.ToLongTimeString();
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongTimeString();
    }
}
  1. 按 F5 鍵建置並執行專案。 請注意,當您按一下 [更新這兩個面板] 時,這兩個標籤都會變更文字;不過,當您按一下 [更新此面板] 時,只有 Label1 更新。

顯示第一個按鈕的螢幕擷取畫面,其中指出 [更新這兩個面板] 和指出 [更新此面板] 的第二個按鈕。

(按一下即可檢視完整大小的影像)

幕後

利用我們剛才建構的範例,我們可以查看 AJAX 所執行的 ASP.NET,以及 UpdatePanel 跨面板觸發程式的運作方式。 為了這樣做,我們將使用產生的頁面來源 HTML,以及名為 FireBug 的 Mozilla Firefox 擴充功能, 我們可以輕鬆地檢查 AJAX 回傳。 我們也會使用 Lutz Roeder 提供的 .NET Reflector 工具。 這兩種工具都可在線上免費取得,而且可在網際網路搜尋中找到。

頁面原始程式碼的檢查幾乎不會顯示一般專案;UpdatePanel 控制項會轉譯為 <div> 容器,我們可以看到 所提供的 <asp:ScriptManager> 腳本資源。 AJAX 用戶端腳本程式庫內部的 PageRequestManager 也有一些新的 AJAX 特定呼叫。 最後,我們看到兩個 UpdatePanel 容器-一個具有轉譯 <input> 按鈕,其中兩 <asp:Label> 個控制項轉譯為 <span> 容器。 (如果您在 FireBug 中檢查 DOM 樹狀結構,您會發現標籤會變暗,表示它們不會) 產生可見的內容。

按一下 [更新此面板] 按鈕,並注意最新的 UpdatePanel 將會隨著目前的伺服器時間更新。 在 FireBug 中,選擇 [主控台] 索引標籤,以便檢查要求。 請先檢查 POST 要求參數:

顯示 [Firebug] 對話方塊的螢幕擷取畫面,其中已選取 [主控台]。

(按一下即可檢視完整大小的影像)

請注意,UpdatePanel 已精確地向伺服器端 AJAX 程式碼指出透過控制項的 UpdatePanel1 ScriptManager1 參數引發的控制項樹狀 Button1 結構。 現在,按一下 [更新這兩個面板] 按鈕。 然後,檢查回應,我們會在字串中看到以管道分隔的變數系列;具體來說,我們會看到最上方的 UpdatePanel UpdatePanel1 ,其 HTML 已傳送至瀏覽器。 AJAX 用戶端腳本程式庫會透過 .innerHTML 屬性以新的內容取代 UpdatePanel 的原始 HTML 內容,因此伺服器會將變更的內容從伺服器傳送為 HTML。

現在,按一下 [更新這兩個面板] 按鈕,並檢查伺服器的結果。 結果非常類似 - 兩個 UpdatePanel 都會從伺服器接收新的 HTML。 如同先前的回呼,會傳送其他頁面狀態。

如我們所見,因為沒有任何特殊程式碼用來執行 AJAX 回傳,所以 AJAX 用戶端腳本程式庫能夠攔截表單回傳,而不需要任何其他程式碼。 伺服器控制項會自動利用 JavaScript,使其不會自動提交表單 - ASP.NET 自動插入程式碼以進行表單驗證和狀態,主要是透過自動腳本資源包含、PostBackOptions 類別和 ClientScriptManager 類別來達成。

例如,請考慮 CheckBox 控制項;會檢查 .NET Reflector 中的類別反組解碼。 若要這樣做,請確定您的 System.Web 元件已開啟,並流覽至 System.Web.UI.WebControls.CheckBox 類別,並開啟 RenderInputTag 方法。 尋找檢查 屬性的條件 AutoPostBack

顯示以 Click 等於開頭之程式碼的螢幕擷取畫面。

(按一下即可檢視完整大小的影像)

當控制項上 CheckBox 啟用自動回傳時,透過 AutoPostBack 屬性 (為 true) ,因此結果 <input> 標記會以其 屬性中的 onclick ASP.NET 事件處理腳本轉譯。 然後,表單提交的攔截可讓 ASP.NET AJAX 插入頁面非干擾性地插入頁面,協助避免可能利用可能不精確的字串取代而可能發生的任何潛在中斷性變更。 此外,這可讓 任何 自訂 ASP.NET 控制項利用 AJAX ASP.NET 的強大功能,而不需要任何其他程式碼來支援其在 UpdatePanel 容器內的使用。

<triggers>此功能會對應至 PageRequestManager 呼叫中所初始化的值,_updateControls (請注意,ASP.NET AJAX 用戶端腳本程式庫會利用以底線開頭的方法、事件和功能變數名稱標示為內部的慣例,而且不適合在程式庫本身之外使用) 。 有了它,我們可以觀察哪些控制項的目的是造成 AJAX 回傳。

例如,讓我們將兩個額外的控制項新增至頁面,將一個控制項完全保留在 UpdatePanels 外部,並在 UpdatePanel 中保留一個控制項。 我們會在上方 UpdatePanel 內新增 CheckBox 控制項,並卸載 DropDownList,其中定義了一些色彩。 以下是新的標記:

清單 3:新標記

<%@ Page Language="C#" AutoEventWireup="true"
 CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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 id="Head1" runat="server">
 <title>Untitled Page</title>
 </head>
 <body>
 <form id="form1" runat="server">
 <asp:ScriptManager EnablePartialRendering="true"
 ID="ScriptManager1" runat="server"></asp:ScriptManager>
 <div>
 <asp:UpdatePanel ID="UpdatePanel1" runat="server"
 UpdateMode="Conditional">
 <ContentTemplate>
 <asp:Label ID="Label1" runat="server" /><br />
 <asp:Button ID="Button1" runat="server"
 Text="Update Both Panels" OnClick="Button1_Click" />
 <asp:Button ID="Button2" runat="server"
 Text="Update This Panel" OnClick="Button2_Click" />
 <asp:CheckBox ID="cbDate" runat="server"
 Text="Include Date" AutoPostBack="false"
 OnCheckedChanged="cbDate_CheckedChanged" />
 </ContentTemplate>
 </asp:UpdatePanel>
 <asp:UpdatePanel ID="UpdatePanel2" runat="server"
 UpdateMode="Conditional">
 <ContentTemplate>
 <asp:Label ID="Label2" runat="server"
 ForeColor="red" />
 </ContentTemplate>
 <Triggers>
 <asp:AsyncPostBackTrigger ControlID="Button1" 
 EventName="Click" />
 <asp:AsyncPostBackTrigger ControlID="ddlColor" 
 EventName="SelectedIndexChanged" />
 </Triggers>
 </asp:UpdatePanel>
 <asp:DropDownList ID="ddlColor" runat="server"
 AutoPostBack="true"
 OnSelectedIndexChanged="ddlColor_SelectedIndexChanged">
 <asp:ListItem Selected="true" Value="Red" />
 <asp:ListItem Value="Blue" />
 <asp:ListItem Value="Green" />
 </asp:DropDownList>
 </div>
 </form>
 </body>
</html>

以下是新的程式碼後置:

清單 4:Codebehind

public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (cbDate.Checked)
        {
            Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
            Label2.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
        }
        else
        {
            Label1.Text = DateTime.Now.ToLongTimeString();
            Label2.Text = DateTime.Now.ToLongTimeString();
        }
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        if (cbDate.Checked)
        {
            Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
        }
        else
        {
            Label1.Text = DateTime.Now.ToLongTimeString();
        }
    }
    protected void cbDate_CheckedChanged(object sender, EventArgs e)
    {
        cbDate.Font.Bold = cbDate.Checked;
    }
    protected void ddlColor_SelectedIndexChanged(object sender, EventArgs e)
    {
        Color c = Color.FromName(ddlColor.SelectedValue);
        Label2.ForeColor = c;
    }
}

此頁面背後的概念是,下拉式清單會選取三種色彩的其中一個來顯示第二個標籤、核取方塊會決定其是否為粗體,以及標籤是否顯示日期及時間。 此核取方塊不應該造成 AJAX 更新,但下拉式清單應該不會儲存在 UpdatePanel 內。

顯示名為 [未命名頁面] 的網頁瀏覽器和下拉式清單的螢幕擷取畫面,其中已選取 [藍色] 按鈕下方顯示 [更新這兩個面板]。

(按一下即可檢視完整大小的影像)

如上述螢幕擷取畫面所示,要按一下的最新按鈕是右按鈕 [更新此面板],該按鈕會更新與下層時間無關的最上層時間。 日期也會在點選之間關閉,因為日期會顯示在底部標籤中。 最後,感興趣的是底端標籤的色彩:它最近已更新為標籤的文字,其示範控制項狀態很重要,而且使用者預期會透過 AJAX 回傳加以保留。 不過,時間並未更新。 當控制項在伺服器上重新轉譯時,ASP.NET 執行時間會透過頁面__VIEWSTATE欄位的持續性自動重新填入時間。 ASP.NET AJAX 伺服器程式碼無法辨識控制項正在變更狀態的方法;它只會從檢視狀態重新填入,然後執行適當的事件。

不過,應該會指出,如果我在Page_Load事件內初始化時間,時間就會正確遞增。 因此,開發人員應該小心適當的程式碼是在適當的事件處理常式期間執行,並避免在控制事件處理常式適當時使用Page_Load。

總結

ASP.NET AJAX Extensions UpdatePanel 控制項很實用,而且可以利用數種方法來識別應該更新它的控制項事件。 它支援由其子控制項自動更新,但也可以回應頁面上其他位置的控制項事件。

若要減少伺服器處理負載的可能性,建議 ChildrenAsTriggers 將 UpdatePanel 的 屬性設定為 false ,並且加入宣告事件,而不是預設包含事件。 這也可防止任何不必要的事件造成潛在的垃圾效果,包括驗證和輸入欄位的變更。 這些類型的 Bug 可能很難隔離,因為頁面會以透明方式更新給使用者,因此原因可能不明顯。

藉由檢查 ASP.NET AJAX 表單後攔截模型的內部運作,我們可以判斷它利用 ASP.NET 所提供的架構。 如此一來,它就會保留與使用相同架構所設計之控制項的最大相容性,並在針對頁面撰寫的任何其他 JavaScript 上最低限度地入侵。

簡歷

Rob Seniorza 是 Terralever (www.terralever.com) 資深 .NET 應用程式開發人員,是 Tempe, AZ 中領先互動式行銷公司。 他可以在 連線 robpaveza@gmail.com 到 ,而他的部落格位於 http://geekswithblogs.net/robp/

Scott Cate 自 1997 年以來一直與 Microsoft Web 技術合作,而且是 myKB.com (www.myKB.com) ,他專門撰寫著重于知識庫軟體解決方案的 ASP.NET 型應用程式。 Scott 可以透過電子郵件連絡, scott.cate@myKB.com 或其部落格位於 ScottCate.com