2010年8月19日

[C#]動態取得UserControl的HTML

使用JQuery來做一些互動性高的網頁操作是非常方便的,尤其運用當中的AJAX方法可以達到逼近桌面程式的效果。前一陣子我在思考如何讓網頁上的每個區塊都是獨立的HTML,然後透過AJAX的方式逐一取得或更新,我個人想到了以下兩個方案

  1. ASP.NET MVC絕對是可以輕鬆辦到這件事情的。
  2. 每個區塊的內容都設計成單一的ASPX網頁,再讓Jquery去依據需要透過AJAX取得網頁內容
Well, 由於我是在既有的系統上必須做到這件事情,因此在這個節骨眼引進ASP.NET MVC對我來說風險太大,因此第一個方案我只好不考慮;第二個方案聽起來還不錯,讓每個區塊的內容都來自不同的Source,在維護上也比較容易些,只是每個網頁產生出來的HTML內容夾雜了許多我不需要的東西,例如HTML、TITLE、BODY、FORM.....等等,我還得逐一處理掉這些,看來也不是挺舒服的方法。後來我想到UserControl,因為UserControl在Render HTML時,只會依據UserControl內設計的元素進行Render,看起來會比ASPX頁面來做Render要俐落許多,因此如果將第二個方案中的ASPX換成UserControl那就再好不過了,只是一般在操作UserControl上都要先在ASPX頁面上進行註冊才能呼叫使用,如下程式碼所示:

<%@ Register src="Menu.ascx" tagname="Menu" tagprefix="uc1" %>
這樣每次若在頁面上新增UserControl就需要增加註冊資訊一次,看在我們這種龜毛工程師的眼裡真是非常不舒服的。所以如果有方法能不需註冊在頁面上就可以產生UserControl的HTML,那真是佛心來的~ 以下的程式碼正是提供這個方法的核心程式,非常簡單!
public class HTMLHelper
{
    //使用委派,可以讓我們在建立UserControl時, 可以執行一些我們需要的動作
    public delegate void InitializeControlDelegate(T ControlToUse);
    public static string RenderUserControl(string ControlPath, InitializeControlDelegate InitControlCallback) where T : UserControl
    {

        //建立新的頁面物件
System.Web.UI.Page pageHolder = new Page();
        //從指定的位置載入UserControl,並轉換為型別T
T ControlToRender = (T)pageHolder.LoadControl(ControlPath);
        //將這個UserControl加入到頁面中
pageHolder.Controls.Add(ControlToRender);  //執行指定的委派工作
        InitControlCallback.Invoke(ControlToRender); 
        //建立一個字串寫入物件
        StringWriter result = new StringWriter(); 

        //使用Server.Execute執行網頁並將網頁內容寫入到 result
System.Web.HttpContext.Current.Server.Execute(pageHolder, result, false); return result.ToString(); //回傳結果 } }
再來讓我們來看看要怎麼用它,因為現在使用.NET 3.5 進行開發,所以可以使用Lamba語法,因此在委派上可以用更簡單的作法:
string _ucHtml = HTMLHelper.RenderUserControl(
                "~/inc/block/GoodCollection.ascx",
                uc =>
                {
                    uc.StorePK = 1;
                    uc.TypePK = 5;
                }
                );
這樣就不單只是叫UserControl產生HTML,也可以在UserControl設計好屬性或方法,讓UserControl依據系統需要產生適當的HTML出來囉。