科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道在不用UpdatePanel的情形下可与ASP.NET AJAX 使用的酷UI模板技术

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

ASP.NET AJAX 提供的内置服务器端控件

作者:scottgu 来源:CSDN 2007年12月31日

关键字: 模板技术 酷UI AJAX

  • 评论
  • 分享微博
  • 分享邮件

通常情形下,当我把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 里按需加载这些模板文件并对其绑定我的数据:

 

查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章