在UpdatePanel中靈活地切換不同用戶控件

 這是一個很常見的使用場景,尤其是出現了UpdatePanel之後:頁面中有一排菜單,點擊菜單中的每一項,都會使某個UpdatePanel中出現不同的控制面板。在開發時,往往會將每個的控制面板寫成不同的用戶控件,點擊菜單時事實上就是在UpdatePanel中放入不同的用戶控件。

  如果要開發這樣的功能,從理論上來說並不困難,但是如果要能夠在控件之間靈活切換,甚至要從控件A的某個操作中切換到控件B,可能就需要增加控件之間的耦合度了。因此,如何控制這樣的切換似乎需要細細考慮一下。

  在這裏,我選擇使用一個第三方的控件來進行統一處理,這個控件就是SwitchPartManager。在瞭解這個控件的實現之前,我們先來看一下一個簡單的使用示例吧。

 

使用效果

  首先,在頁面中,會使用兩個按鈕在兩個用戶控件之間進行切換。在SwitchPartManager的PlaceHolderUpdatePanelID屬性指定了作爲容器的UpdatePanel,而點擊不同的按鈕,則會調用ScriptManager的SwitchTo方法切換至不同的控件。如下:

Default.aspx
<jeffz:SwitchPartManager ID="SwitchPartManager1" runat="server" PlaceHolderUpdatePanelID="UpdatePanel1" /> <asp:Button ID="ButtonA" runat="server" Text="ControlA" OnClick="ButtonA_Click" /> <asp:Button ID="ButtonB" runat="server" Text="ControlB" OnClick="ButtonB_Click" /> <hr /> <asp:UpdatePanel ID="UpdatePanel1" runat="server"></asp:UpdatePanel>
Default.aspx.cs
protected void Page_Load(object sender, EventArgs e) { ScriptManager sm = ScriptManager.GetCurrent(this); sm.RegisterAsyncPostBackControl(this.ButtonA); sm.RegisterAsyncPostBackControl(this.ButtonB); } protected void ButtonA_Click(object sender, EventArgs e) { SwitchPartManager.GetCurrent(this).SwitchTo("ControlA"); } protected void ButtonB_Click(object sender, EventArgs e) { SwitchPartManager.GetCurrent(this).SwitchTo("ControlB"); }

 

  在ControlA中有一個按鈕,點擊它之後將會切換到ControlB。如下:

ControlA.ascx
This is Control A. <asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">Switch To Control B</asp:LinkButton>
ControlA.ascx.cs
protected void LinkButton1_Click(object sender, EventArgs e) { SwitchPartManager.GetCurrent(this.Page).SwitchTo("ControlB"); }

 

  而在ControlB中,它自身含有一個UpdatePanel和一個按鈕,點擊按鈕則可以刷新時間:

ControlB.ascx
This is Control B <br /> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <%= DateTime.Now %> <asp:Button ID="Button1" runat="server" Text="Refresh Time" /> </ContentTemplate> </asp:UpdatePanel>

 

  編寫代碼,控件之間的切換都是非常的容易。大家可以點擊這裏查看使用效果。

 

SwitchPartManager控件實現

  實現這麼一個控件其實比想象中容易許多。處理這個問題的關鍵在於如何在(同步或異步)PostBack後正確地恢復當前已經加載的控件。只要能夠正確恢復了控件的狀態,剩下的問題都是由ASP.NET自身的機制來完成了,例如觸發事件等等。

  我們來看一下SwitchPartManager的關鍵實現代碼:

SwitchPartManager關鍵代碼
[PersistChildren(false)] [ParseChildren(true)] [NonVisualControl] public class SwitchPartManager : Control { private const string HiddenElementName = "__PartType__"; private bool initialized = false; private string partTypeToSave = null; public static SwitchPartManager GetCurrent(Page page) { return page.Items[typeof(SwitchPartManager)] as SwitchPartManager; } protected override void OnInit(EventArgs e) { base.OnInit(e); if (this.Page.Items.Contains(typeof(SwitchPartManager))) { throw new InvalidOperationException("One SwitchPartManager per page."); } this.Page.Items[typeof(SwitchPartManager)] = this; this.Page.InitComplete += new EventHandler(Page_InitComplete); this.Page.PreRenderComplete += new EventHandler(Page_PreRenderComplete); } private void Page_InitComplete(object sender, EventArgs e) { this.initialized = true; string partType = this.Page.Request.Params[SwitchPartManager.HiddenElementName]; if (partType != null) { this.SwitchTo(partType); } } private void Page_PreRenderComplete(object sender, EventArgs e) { if (!String.IsNullOrEmpty(this.partTypeToSave)) { ScriptManager.RegisterHiddenField(
this.Page, SwitchPartManager.HiddenElementName, this.partTypeToSave); } } // 得到作爲容器的UpdatePanel private UpdatePanel PlaceHolderUpdatePanel { get { // ... } } public void SwitchTo(string partType) { Control container = this.PlaceHolderUpdatePanel.ContentTemplateContainer; container.Controls.Clear(); Control control = this.Page.LoadControl(partType + ".ascx"); control.ID = "JustToPreserveUniqueName"; container.Controls.Add(control); this.partTypeToSave = partType; } }

 

  SwitchTo方法是用於切換用戶控件的方法,它會將UpdatePanel內已有的控件(例如從ControlA切換到ControlB時,UpdatePanel中已經有了ControlA)清除,然後再向UpdatePanel中添加新的控件。

  我在這裏將當前當前的控件標識記錄在私有變量partTypeToSave中,它會在Page的PreRenderComplete時作爲<input type="hidden" />的形式輸出。我在這裏使用了HiddenField作爲保留控件選擇狀態的方式,這樣可以避免因爲ViewState被禁用而導致的數據丟失。

  這樣,我們的頁面在PostBack之後,就能夠通過接受到的信息來恢復UpdatePanel的控件了。我在在Page的InitComplete時恢復UpdatePanel中的控件——很容易,直接使用SwitchTo方法就可以了。

  這幾乎就是SwitchPartManager的完整代碼。其實這個類相當的簡單,但是它的價值卻不小。但是根據我的經驗,似乎爲了自己的項目開發Custom Control的朋友不多,大家大都是在寫用戶控件(ascx)。其實在有些時候,爲自己的應用編寫一個Custom Control,尤其是用於“管理”的控件,其實能夠使頁面的邏輯變得清晰許多。

 

  點擊這裏下載SwitchPartManager的代碼。

備註:本文引用自http://www.cnblogs.com/JeffreyZhao/archive/2007/03/29/SwitchPartManager.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章