首頁  >  文章  >  web前端  >  使用UserControl做HTML產生的技巧

使用UserControl做HTML產生的技巧

高洛峰
高洛峰原創
2017-03-08 15:58:341189瀏覽

User Control大家一定不會陌生,在使用ASP.NET的過程中,除了aspx頁面,最常見的就莫過於ascx了。 ascx是一個有獨立邏輯的元件,提供了強大的複用特性,合理使用,能夠大幅提高開發效率。透過User Control直接產生HTML內容其實已經是比較常用的技巧了(尤其在AJAX時代),不過網路上這方面的內容比較少,很多人還是在苦苦地拼接字串,因此在這裡我透過一個實例簡單介紹一下這個技巧。

對一個物件(文章,圖片,音樂,etc.)進行評論是應用中最常見的功能之一。首先,我們定義一個Comment類,以及其中會用到的「取得」方法:

public partial class Comment{    public DateTime CreateTime { get; set; } 
    public string Content { get; set; }
} 
public partial class Comment{    private static List<Comment> s_comments = new List<Comment>
    {        new Comment
        {
            CreateTime = DateTime.Parse("2007-1-1"),
            Content = "今天天气不错"
        },        new Comment
        {
            CreateTime = DateTime.Parse("2007-1-2"),
            Content = "挺风和日丽的"
        },        new Comment
        {
            CreateTime = DateTime.Parse("2007-1-3"),
            Content = "我们下午没有课"
        },        new Comment
        {
            CreateTime = DateTime.Parse("2007-1-1"),
            Content = "这的确挺爽的"
        }
    }; 
    public static List<Comment> GetComments(int pageSize, int pageIndex, out int totalCount)
    {
        totalCount = s_comments.Count; 
        List<Comment> comments = new List<Comment>(pageSize); 
        for (int i = pageSize * (pageIndex - 1);
            i < pageSize * pageIndex && i < s_comments.Count; i++)
        {
            comments.Add(s_comments[i]);
        } 
        return comments;
    }
}

為了顯示一個評論列表,我們可以使用一個使用者控制項(ItemComments.aspx)來封裝。自然,分頁也是必不可少的:

<asp:Repeater runat="server" ID="rptComments">
    <ItemTemplate>
        时间:<%# (Container.DataItem as Comment).CreateTime.ToString() %><br />
        内容:<%# (Container.DataItem as Comment).Content %> 
    </ItemTemplate>
    <SeparatorTemplate>
        <hr />
    </SeparatorTemplate>    <FooterTemplate>
        <hr />
    </FooterTemplate></asp:Repeater> <% if (this.PageIndex > 1)
   { %>
        <a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页">上一页</a> <% } %><% if (this.PageIndex * this.PageSize < this.TotalCount)
   { %>

還有:

public partial class ItemComments : System.Web.UI.UserControl{    protected override void OnPreRender(EventArgs e)
    {        base.OnPreRender(e); 
        this.rptComments.DataSource = Comment.GetComments(this.PageSize,            this.PageIndex, out this.m_totalCount);        this.DataBind();
    } 
    public int PageIndex { get; set; } 
    public int PageSize { get; set; } 
    private int m_totalCount;    public int TotalCount
    {        get
        {            return this.m_totalCount;
        }
    }
}

然後再頁面(ViewItem.aspx)中使用這個元件:

<p id="comments"><demo:ItemComments ID="itemComments" runat="server" /></p>

#以及:

public partial class ViewItem : System.Web.UI.Page{    protected void Page_Load(object sender, EventArgs e)
    {        this.itemComments.PageIndex = this.PageIndex;
    } 
    protected int PageIndex
    {        get
        {            int result = 0;            Int32.TryParse(this.Request.QueryString["page"], out result); 
            return result > 0 ? result : 1;
        }
    }
}

開啟ViewItem.aspx之後效果如下:

時間:2007/1/1 0:00:00 內容:今天天氣不錯


時間:2007/1/2 0:00:00 內容:挺風和日麗的


時間:2007/1/3 0:00:00 內容:我們下午沒有課


下一頁

這張頁面的功能非常簡單,那就是察看評論。目前評論的頁碼會使用QueryString的page項目進行指定,然後在ViewItem.aspx裡取得到並且設定ItemComments.ascx控制項的屬性。 ItemComments控制項會根據自身屬性來取得數據,進行綁定,至於顯示內容,全都定義在ascx中了。由於需要分頁功能,這個評論控件中還包含了上一頁和下一頁的鏈接,他們鏈接的目標很簡單,就是ViewItem.aspx頁,並且加上頁碼的Query String而已。

功能是完成了,不過用著用著忽然覺得不妥,為什麼呢?因為我們在翻頁,或是用戶發布評論的時候,整張頁面都刷新了。這可不好,要知道可能ViewItem頁中還有其他幾個顯示部分,它們可是不變的。而且如果其他幾個部分也需要分頁,那麼可能就需要保留頁面上每個部分的當前頁碼,這樣開發的複雜性還是比較高的。

那我們不如用AJAX。無論是用戶察看評論時進行翻頁或發表評論,都不會對頁面上的其他內容造成影響。要開發這個功能,自然需要伺服器端的支持,那該怎麼做呢?一般我們總是有兩種選擇:

  1. 伺服器端回傳JSON數據,在客戶端操作DOM進行呈現。

  2. 伺服器端直接傳回HTML內容,然後在客戶端設定容器(例如上面id為comments的p)。

不過無論採用哪一種做法,「呈現」的邏輯一般總是會被另寫一遍(第一次的呈現邏輯寫在了ItemComments.ascx中)。如果使用第1種做法,那麼呈現邏輯就需要在客戶端透過操作DOM進行呈現;如果使用第2種做法,那麼就要在伺服器端進行字串拼接。無論哪種做法都違反了DRY原則,當ItemComments.ascx裡的呈現方式修改時,另一處也要跟著修改。而且無論是操作DOM元素或是拼接字串維護起來都比較麻煩,開發效率自然就不高了。

如果我們能夠直接從ItemComments控制項取得HTML內容該有多好啊-那麼我們就這麼做吧。請看如下程式碼(GetComments.ashx):

public class GetComments : IHttpHandler{    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain"; 
        ViewManager<ItemComments> viewManager = new ViewManager<ItemComments>();        
        ItemComments control = viewManager.LoadViewControl("~/ItemComments.ascx");
 
        control.PageIndex = Int32.Parse(context.Request.QueryString["page"]);
        control.PageSize = 3;
 
        context.Response.Write(viewManager.RenderView(control));
    } 
    public bool IsReusable { ... }
}

很簡單的程式碼,不是嗎?建立對象,設定屬性,然後透過Response.Write輸出而已。實在沒什麼大不了的——不過關鍵就在於ViewManager類,我們來看看它是怎麼實現的:

public class ViewManager<T> where T : UserControl{    private Page m_pageHolder; 
    public T LoadViewControl(string path)
    {        this.m_pageHolder = new Page();        return (T)this.m_pageHolder.LoadControl(path);
    } 
    public string RenderView(T control)
    {        StringWriter output = new StringWriter(); 
        this.m_pageHolder.Controls.Add(control);        HttpContext.Current.Server.Execute(this.m_pageHolder, output, false); 
        return output.ToString();
    }
}

ViewManager中只有兩個方法:LoadViewControl和RenderView。 LoadViewControl方法的作用是建立一個Control實例並傳回,RenderView方法的作用則就是產生HTML了。這個實現方式的技巧在於使用了一個新建的Page物件作為生成控制項的“容器”,而最後其實我們是將Page物件的整個生命週期運行一遍,並且將結果輸出。由於這個空的Page物件不會產生任何其他程式碼,因此我們得到的,就是用戶控制項產生的程式碼了。

不過要達到這個AJAX效果,還需要做兩件事情。

第一,就是簡單修改一下ItemComments控制項中的翻頁鏈接,讓它被點擊時呼叫一個JavaScript函數。例如「上一頁」的程式碼就會變成:

<a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页"    
onclick="return getComments(<%= this.PageIndex - 1 %>);">上一页</a>

第二,就是實作getComments這個客戶端方法。這裡我使用了prototype框架,好處就是能夠用相當簡潔的程式碼來做到取代HTML的AJAX效果:

<script type="text/javascript" language="javascript">
    function getComments(pageIndex)
    {        new Ajax.Updater(            "comments",            "/GetComments.ashx?page=" + pageIndex + "&t=" + new Date(),
            { method: "get" }); 
        
        return false; // IE only
    }</script>

大功告成。

其實就像之前所說的那樣,使用UserControl進行HTML程式碼產生是一個十分常用的技巧。尤其在AJAX應用程式越來越普及的情況下,合理使用上述的方式可以方便的為我們的應用添加AJAX效果。而且很多情況下,我們即使不需要在頁面上顯示內容,也可以將內容使用UserControl編輯。因為編寫UserControl比拼接字串的方式無論是在開發效率或可維護性上都高出許多。由於這個方式其實使用了WebForms這個久經考驗的模型,因此在執行效率方面也是相當高的。此外,就剛才的範例來說,使用UserCotrol進行HTML產生還有其他好處:

  1. 頁面呈現邏輯只實作了一次,提升了可維護性。

  2. 不會影響頁面的SEO,因為在客戶端6dc338e96418ddb2f62886b029f4122c的href還是有效的。

事實上,WebForms是一個非常強大的模型,所以ASP.NET MVC的View也使用了WebForms的引擎。透過上面這個例子,我們其實還可以做到其他很多東西──例如用UserControl來產生XML數據,因為UserControl本身不會帶來任何額外的內容。

以上是使用UserControl做HTML產生的技巧的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn