在不用UpdatePanel的情形下可與ASP.NET AJAX 使用的酷UI模板技術

來源:互聯網
上載者:User

【原文地址】Tip/Trick: Cool UI Templating Technique to use with ASP.NET AJAX for non-UpdatePanel scenarios
【原文發表日期】 Sunday, October 22, 2006 9:02 PM

這個周末我一直饒有興趣地在玩ASP.NET AJAX Beta版。

通常情形下,當我把AJAX功能整合進我的編碼時,我最後總是使用 ASP.NET AJAX 提供的內建伺服器端控制項(譬如UpdatePanel和UpdateProgress等)以及ASP.NET AJAX控制項工具包裡的那些酷控制項。Scott Hanselman 兩個星期前在他最近的一次 podcast 中採訪我時開玩笑地聲稱,使用這些AJAX控制項簡直是“作弊(cheating)”, 因為在大多數常見的情形下,它們不需要你寫任何的用戶端JavaScript編碼。

這個周末,我決定把我的編程集中在 ASP.NET AJAX 架構中根本不使用UpdatePanel的一些用戶端JavaScript 庫函數上,實驗另外的方式用伺服器來輕鬆地產生HTML UI,然後把這些HTML通過AJAX動態地注入頁面內。在這個過程中,我建立了一個我認為是比較有用的庫,這個庫可以和ASP.NET AJAX 以及其他 AJAX 庫一起使用,來提供一個很好的ASP.NET模板UI機制,它不使用也不需要象 postback 和 viewstate 這樣的概念,但仍舊提供了控制項封裝和簡易重用的好處。

首先,ASP.NET AJAX中JavaScript 網路層(Networking Stack)的一些簡短的背景知識

在開始討論我上面提到的模板方法之前,先提供一些ASP.NET AJAX中用戶端JavaScript庫方面的背景知識,讓我們首先來建立一個簡單的AJAX "hello world" 應用。這個應用允許使用者輸入一個名字,點擊一個按鈕,然後在用戶端使用JavaScript向伺服器做一個AJAX調用,進而輸出一個訊息:

ASP.NET AJAX 包含了一個非常靈活的JavaScript 網路程式庫 (network library stack),對.NET 資料類型有著豐富的序列化支援。你可以在伺服器端定義可從用戶端JavaScript 裡調用的方法,要麼是你的 ASP.NET 頁面類裡的靜態方法,要麼給你的ASP.NET應用添加一個web服務,這個服務須飾以 [Microsoft.Web.Script.Services.ScriptService] 中繼資料屬性,而呈示的方法則須飾以標準的 [WebMethod] 屬性。

例如,下面是個SimpleService.asmx web服務,內含一個GetMessage方法,該方法接受一個字串參數:

 

using System;
using System.Web.Services;

[Microsoft.Web.Script.Services.ScriptService]
public class SimpleService : WebService {

    [WebMethod]
    public string GetMessage(string name) {
        return "Hello <strong>" + name + "</strong>, the time here is: " + DateTime.Now.ToShortTimeString();
    }
}

 

ASP.NET AJAX 然後可以自動建立一個JavaScript代理類,可在用戶端用來調用這個方法,以及傳遞合適的參數。添加這個JavaScript代理類最容易的方法是在頁面上添加一個 <asp:ScriptManager> 控制項,然後指向web服務的端點。(這個控制項同時也確保每個庫在頁面只被載入一次。)

然後我就可以調用這個方法,把文字框裡的值傳給它,用象下面這樣的用戶端 JavaScript 編碼設定好一個回調事件處理器,定在伺服器響應時觸發。註:我可以把 JavaScript 編碼寫得更加花哨,去掉其中的幾行代碼,但我目前是故意要保持清晰和簡單,以避免故弄玄虛:

 

<html>
<head id="Head1" runat="server">
    <title>Hello World Service</title>
    <link href="StyleSheet.css" rel="stylesheet" type="text/css" />
    
    <script language="javascript" type="text/javascript">
        
        function callServer() {
            SimpleService.GetMessage( $get("Name").value, displayMessageCallback );
        }
    
        function displayMessageCallback(result) {
            $get("message").innerHTML = result;
        }
    
    </script>
                
</head>
<body>
    <form id="form1" runat="server">
        
        <asp:ScriptManager ID="ScriptManager1" runat="server" >
            <Services>
                <asp:ServiceReference Path="~/SimpleService.asmx" />
            </Services>
        </asp:ScriptManager>
        
        <h1>Hello World Example</h1>
        
        <div>
            Enter Name: <input id="Name" type="text" />
            
            <a href="BLOCKED SCRIPTcallServer()">Call Server</a>

            <div id="message"></div>
        </div>
        
    </form>
</body>
</html>

 

這樣,當我運行這個頁面,輸入一個名字,Scott,頁面就會使用AJAX 回調,動態更新頁面上的HTML,而不需要任何postback或頁面更新。

使用模板產生HTML的一個比較乾淨的的做法

你可以從上面的例子看出,我可以很輕鬆地從伺服器端返回HTML,在用戶端把它注入頁面。但是,我的這個做法的一個缺點是,我把產生HTML的邏輯直接參雜到我的伺服器web method裡了。這個做法不好,因為,1) 混雜了UI和邏輯編碼,2) 隨著 UI 愈加豐富,編碼將會變得難以維護和編寫。

我想要的是一個簡易的方法,在我的web service方法裡執行我的邏輯,擷取資料,然後把資料傳給某個模板或視圖類來產生要返回的 HTML UI 結果。譬如,考慮產生一個客戶/訂單管理的應用,在其中使用AJAX來產生類似這樣的一個客戶列表UI:

我想要在我的 WebService 裡編寫象下面這樣的伺服器端編碼來按國家查詢客戶,然後返回一個合適的HTML列表UI。注意到下面的ViewManager.RenderView 方法是如何允許我傳進一個資料對象來綁定UI的。所有的UI產生編碼都移出了我的控制器webmethod,都封裝在我的View裡了:

 

    [WebMethod]
    public string GetCustomersByCountry(string country)
    {
        CustomerCollection customers = DataContext.GetCustomersByCountry(country);

        if (customers.Count > 0)
            return ViewManager.RenderView("customers.ascx", customers);
        else
            return ViewManager.RenderView("nocustomersfound.ascx");
    }

結果是,這並不是很難,只需要20行左右的代碼就實現了 ViewManager 類和上面用到的 RenderView 方法。你可以在這裡下載這個簡單的實現。

我的實現允許你使用標準的ASP.NET 使用者控制項 (.ascx 檔案)模型來定義一個顯示模板,這意味著你擁有完全的VS設計器支援, intellisense,和編譯檢查。它並不要求你一定要用一個頁面來包含這個使用者控制項,實際上,我的 RenderView 實現在顯示時動態地產生一個空Page對象來包含這個使用者控制項,把顯示記錄下來,以一個字串的形式返回。

譬如,下面這個Customer.ascx模板,我可以用它來產生象上面那個裡的客戶列表輸出。它產生了一串客戶的名字,每個客戶有一個串連,指向他們的訂單曆史細節:

 

<%@ Control Language="C#" CodeFile="Customers.ascx.cs" Inherits="Customers" %>

<div class="customers">

    <asp:Repeater ID="Repeater1" runat="server">
        <ItemTemplate>
        
            <div>    
                <a href="BLOCKED SCRIPTCustomerService.GetOrdersByCustomer('<%# Eval("CustomerID") %>', displayOrders)">
                    <%# Eval("CompanyName") %>
                </a>
            </div>

        </ItemTemplate>
    </asp:Repeater>

</div>

 

相關的後端代碼是這樣的(注,如果我想的話,我可以往裡面添加特定視圖的格式化方法):

 

using System;

public partial class Customers : System.Web.UI.UserControl
{
    public object Data;

    void Page_Load(object sender, EventArgs e)
    {
        Repeater1.DataSource = Data;
        Repeater1.DataBind();
    }
}

 

為了把資料傳進模板,(譬如,上面這個customers 集合),我一開始時要求每個UserControl 實現一個IViewTemplate 介面,通過它我可以將資料與UserControl 相關聯。但玩了一陣後,我決定使用一個更簡單的使用者模型,讓UserControl 呈示一個如上面所示的公開的Data屬性。然後,ViewManager.RenderView 方法通過反射把傳給它本身的資料對象與UserControl執行個體相關聯,之後,UserControl的行為就象一個普通使用者控制項一樣。

最後得到的結果是一個非常強有力而且簡易的方式,它可以產生你想要的任何類型的HTML回複,而且非常乾淨地封裝在.ascx 模板檔案裡了。

最後的加工

你可以在這裡下載我最後建立的範例的完整編碼。為好玩,我給上面那個客戶列表例子另添加了功能,在按國家查詢返回客戶列表後,使用者可以點擊任何一個客戶的名字,然後就跳出一個相應客戶的訂單表(還有他們下訂單的日期)。這也是用我上面描述的方法完全通過AJAX來實現的:

整個應用在用戶端只有8行JavaScript編碼,在伺服器端總共有15行編碼(包括資料訪問的所有代碼)。所有的HTML UI產生編碼是封裝在4個.ascx模板檔案裡的,我可以從我的 webmethod 裡按需載入這些模板檔案並對其綁定我的資料:

點擊這裡下載ViewManager.RenderView的編碼,如果你想看看,試用一下的話。

希望本文對你有所協助,

Scott

 

修改後可啟動並執行樣本程式:AjaxSample

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.