UpdatePanel
對於UpdatePanel控制項的使用是ASP.NET AJAX Extentions的重要部分。我們收到了關於它和UpdateProgress控制項的大量使用者反饋。為了增強局部重新整理的功能我們作了多處修改,並加強了UpdatePanel對於控制項的相容性。我們也為非同步PoskBack實現了一個豐富的事件模型,這樣您就可以在用戶端響應它們並對頁面更新提供額外操作了。
ScriptManager Control
在RTM版本中,ScriptManager有一個EnablePartialRendering屬性,其預設值為true,這減少了使用UpdatePanel來做非同步頁面局部重新整理所需的步驟。
為了降低控制項的複雜程度,ScriptManager的ErrorTemplate屬性在RTM版本中被去除了。現在錯誤處理的模型變得更加靈活,例如您可以為它建立一個獨立的伺服器控制項。另外,您現在也可以使用ScriptManager的AsyncPostBackErrorMessage屬性,不過它只是設定了預設的錯誤資訊,如果您需要動態地自訂的錯誤資訊的話,您可以使用AsyncPostBackError事件。
現在ScriptManager暴露出了一個新的屬性AsyncPostBackTimeout,以此控制非同步PostBack的逾時時間。
值得一提的是,伺服器控制項目前可能會使用到ScriptManager中新增的註冊方法。這個方法增加了對於UpdatePanel使用的支援,並減少了CTP版本中UpdatePanel的複雜性。現在的資源已經包括了指令碼,樣式表,Hidden Field等。ClientScriptManager中的方法與上述方法相對應。它們能夠接受一個控制項執行個體作為參數,這樣如果在UpdatePanel中使用這些控制項,他們所需的指令碼就能被正確跟蹤了。
Dynamic UpdatePanel Controls
現在有兩種在頁面中動態添加UpdatePanel的方法,這是RTM版本中最大的改進。使用動態UpdatePanel的方法是:
- 編寫自訂控制項的開發人員現在能夠將UpdatePanel控制項添加到群組控制項中。這樣,只要頁面中存在ScriptManager並且其EnablePartialRendering設為true,這樣就能使用該自訂控制項並得到局部重新整理的體驗了。並且,如果頁面中沒有ScriptManager,也能在傳統PostBack模型中正常使用該控制項。
- 頁面開發人員能夠在其他控制項的模版中添加UpdatePanel。
下面的樣本展示了如何在自訂控制項中使用UpdatePanel控制項。protected override void CreateChildControls() {
base.CreateChildControls();
ScriptManager sm = ScriptManager.GetCurrent(Page);
Control parent;
Control container;
if (sm == null || !sm.EnablePartialRendering) {
// If not doing partial rendering, use a
// dummy control as the container.
parent = container = new Control();
}
else {
// Create an UpdatePanel control.
UpdatePanel up = new UpdatePanel();
// Instead of adding child controls directly to
// the UpdatePanel control, add them to its
// ContentTemplateContainer.
container = up.ContentTemplateContainer;
parent = up;
}
AddDataControls(container);
Controls.Add(parent);
}
Client Events During Asynchronous Postbacks
在CTP版本中,用戶端PageRequestManager對象依靠XMLHttpRequest對象來實現非同步PoskBack並處理Response。在RTM版本中,PageRequestManager對象提供了一個非同步PoskBack的生命週期事件,您能夠使用它們自訂處理Request和Response的方式。以下為可用的用戶端事件,並且提供了事件所需的參數資訊:
- initializeRequest:您能夠使用這個事件來取消即將發送的非同步PostBack請求,它也能夠讓您根據PostBack資訊來做一些額外的工作。這個事件的參數為InitializeRequestEventArgs類型。
- beginRequest:您能夠使用該事件來啟動某些工作,例如您可以在這個事件中顯示Progress並且在endRequest事件中再將其隱藏。這個事件的參數為BeginRequestEventArgs。
- pageLoding:您能夠使用這個事件中為UpdatePanel的即將更新或刪除進行一些額外的工作,例如釋放資源。您也可以在響應這個事件時檢查伺服器端發送過來的自訂資訊,以此進行一些自訂工作。這個事件的參數為PageLoadingEventArgs類型。
- pageLoaded:這個事件和pageLoading事件相似,它提供了非同步PostBack結果所建立的UpdatePanel的資訊。這個事件的參數為PageLoadedEventArgs類型。
- engRequest:您能夠使用這個事件來自訂錯誤處理方式,處理伺服器端發送的額外資訊等工作。您可以使用它來隱藏UpdateProgress控制項。這個事件的參數為EndRequestEventArgs類型。
Developing Controls Compatible with the UpdatePanel Control
在CTP版本中,UpdatePanel控制項會處理許多被輸出的對象,甚至包括不在UpdatePanel中的控制項,然後在頁面上進行完整的更新。這使一些控制項無法和UpdatePanel相容了。例如,在CTP版本中,如果在UpdatePanel動態添加ASP.NET驗證控制項的話,它們便無法正確工作了,這種情形在使用Wizard控制項的每一步中驗證使用者輸入時尤為常見。
在RTM版本中改變了UpdatePanel的模型。您可以使用註冊指令碼類庫相同的辦法,向ScriptManager註冊將要發送到用戶端的指令碼或資料。在RTM版本中包括了一組新的ASP.NET驗證控制項,它們會將自己的指令碼使用ScriptManager註冊。這些新控制項的Tag名與ASP.NET原有的驗證控制項相對應,因此您不需要改變在頁面中聲明建立的驗證控制項。不過,如果在UpdatePanel內部使用了驗證控制項的話,您需要改變代碼以使用新的控制項。
下面的樣本展示了RTM版本中的一個相容UpdatePanel的自訂控制項。如下:protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
Control control = FindControl(_controlID);
// Register scripts with new ScriptManager APIs.
// The scripts hook up new PageRequestManager events.
string script = String.Format(
CultureInfo.InvariantCulture,
@"var {0}_hover =
new Microsoft.Samples.HoverExtender(document.getElementById('{1}'), '{2}');
{0}_hover.attach();",
ClientID,
control.ClientID,
ColorTranslator.ToHtml(BackgroundColor));
ScriptManager.RegisterClientScriptInclude(
this, typeof(HoverExtender), "HoverExtenderScript",
ResolveClientUrl("~/ScriptLibrary/HoverExtender.js"));
ScriptManager.RegisterStartupScript(
this, typeof(HoverExtender), ClientID, script, true);
}
Sending Additional Data to the Client
在CTP版本中,有個功能比較難以實現,那就是在非同步PoskBack頁面後,根據從伺服器端收到的資料更新UpdatePanel外的控制項。在RTM版本中可以通過調用ScriptManager的一個方法將資料註冊並輸出到頁面,以此解決這個問題。
試想,如果需要使用伺服器的代碼來改變用戶端的Timer控制項的interval和enabled屬性的值,但是這個Timer卻不在UpdatePanel中。在CTP版本中是無法做到這一點的。
在RTM版本中,ScriptManager在伺服器段儲存了一個字典對象,您可以使用RegisterDataItem方法來更新和註冊對象。這個字典會被發送到用戶端,您可以在用戶端的pageLoading,pageLoaded和endRequest事件中通過eventArgs.get_dataItems()方法獲得該字典對象。
下面的樣本展示了註冊資料的方法:// Server control code.
...
public int interval {
get {...}
set {
_data = value;
...
}
}
void PreRender() {
ScriptManager sm1 = ScriptManager.GetCurrent(Page);
if (sm1 != null && sm1.IsInAsyncPostBack) {
ScriptManager.RegisterDataItem(this, _data.ToString());
}
// The control also needs to register script to handle the
// endRequest event on the client and retrieve this value.
// The script below adds a handler for the current instance
// of the PageRequestManager object and calls the
// get_dataItem() method from eventArgs.
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), key, script)
}
Comment
上面的代碼最有意思的可能是最後一行,它的作用是在用戶端的PageRequestManager對象中註冊一個endRequest的handler,以此來做一些修改或者別的工作。其實有了這個方法之後,即使沒有向用戶端輸出DataItem的支援,也已經能夠在操作用戶端對象了。有了DataItem這一功能之後,可能更重要的作用就是能夠使伺服器端代碼和用戶端代碼分開,分別進行集中地維護。
Custom Error Handling and Redirection
在CTP版本中並沒有提供控制錯誤的辦法,甚至沒有自訂錯誤的設定。在RTM版本中則解決了這個問題。
在ScriptManager對象裡提供了一個屬性:AllowCustomError。當該屬性被設為false時,ScriptManager對象會覆蓋自訂的錯誤跳轉,並將錯誤資訊發送到用戶端,這樣您就可以將錯誤資訊顯示出來,而避免了頁面被轉向到其他地方。
在RTM版本中是通過一個額外的Redirct Module來控制頁面轉向的。因此,在RTM版本中已經能夠處理跨頁面的Posting的情況。
Triggers
在CTP版本中,ScriptManager控制項使用了ControlValueTrigger和ControlEventTrigger類型,並將它們存放一個觸發器集合中,以此將這些觸發器綁定到頁面的控制項上去。在RTM版本中,兩者被集中到了一個類型:AsyncPostBackTrigger,以此避免以前的兩個觸發器可能帶來的混亂狀況。
根據使用者反饋,我們增加了一個PostBackTrigger對象,它提供了了從UpdatePanel內部產生頁面完全(同步)PostBack的能力。這個Trigger對象現在也能夠與實現了IPostbackEventHandler,IPostbackDataHandler或者INamingContainer介面的控制項配合使用。
AsyncPostBackTrigger能夠使UpdatePanel觸發非同步PostBack更新。這個觸發器也能指向UpdatePanel外部的控制項,或者指向控制項的階層中的父控制項。當一個作為naming container的控制項被指定為觸發器,則它內部的所有控制項所引發的PoskBack都和這個觸發器的行為相同。
下面的例子展示了AsyncPostBackTrigger對象聲明形式的使用方法:<asp:Button runat="server" id="Button1" Text="Go" />
<asp:UpdatePanel ID="UP1" UpdateMode="Conditional" runat="server">
<ContentTemplate>...</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" />
</Triggers>
</asp:UpdatePanel>
一個PostBackTrigger能夠指向一個UpdatePanel內部的控制項,使它能產生普通的PostBack。這些控制項必須是當前UpdatePanel內部的控制項。
UpdateProgress Control
在RTM版本中增強了UpdateProgress控制項,使它具有了一個額外的功能:指定一個時間間隔,只有非同步PostBack超出這個時間後才顯示Progress控制項。您也可以控制UpdateProgress的輸出來控制這個控制項在隱藏時是否會佔用頁面的空間,就像設定ASP.NET驗證控制項的DisplayMode屬性一樣。另外,您還可以通過增加幾行代碼,為Progress UI添加一個取消的功能。
下面的例子展示了如何設定UpdateProgress控制項,使它只在PostBack超過半秒(500毫秒)之後才顯示出來:<asp:UpdateProgress runat=server ID="Progress1" DisplayAfter="500">
<ProgressTemplate>
<b>Working on request...</b>
<input type="button" id="abortButton" onclick="abortPB()" value="Cancel" />
</ProgressTemplate>
</asp:UpdateProgress>
<script type="text/javascript">
function abortPB() {
var obj = Sys.WebForms.PageRequestManager.getInstance();
if (obj.get_isInAsyncPostBack()) {
obj.abortPostBack();
}
}
</script>