在使用jTemplate插件一文中我们共同领略了jTemplate插件带给我们的灵活,在这个JSON表现尤为流行和广泛支持的时代,这无疑给了我们很大的便利来提供更好的UX(User eXperience)。在ASP.NET AJAX(目前为Preivew3)4.0中也提供了类似的功能,今天我们就来一起看看如何使用ASP.NET AJAX 4.0 Template。
引入AJAX类库和相关命名空间
要使用ASP.NET AJAX 4.0必须首先获得4.0的JS类库。你可以在CodePlex上得到:http://www.codeplex.com/aspnet/Wiki/View.aspx?title=AJAX&referringTitle=Home。 AJAX4.0提供了对ADO.NET Data Service的客户端支持,数据模板,数据源和数据视图控件,以及数据绑定和其他一些功能。下载的类库中有两个JS文件:MicrosoftAjaxTemplates.js和MicrosoftAjaxAdoNet.js。首先将其引用到页面文件中,为了使用DataView和Template功能,需要导入相关命名空间:
<body xmlns:sys="javascript:Sys" xmlns:dv="javascript:Sys.UI.DataView" sys:activate="*"> <form id="form1" runat="server"> <asp:ScriptManager ID="manager1" runat="server"> <Scripts> <asp:ScriptReference Path="~/Library/MicrosoftAjaxAdoNet.js" /> <asp:ScriptReference Path="~/Library/MicrosoftAjaxTemplates.js" /> </Scripts> </asp:ScriptManager> </body> |
这里我么引入了sys命名空间和Sys.UI.DataView命名空间。因为这是相关控件在JS类库中所在的命名空间。sys:activate表明拥有sys:atacth标记的element将在当前的文档中激活,这样在将模板附加到DataView时将会生效。*表示激活所有元素。
定义简单的模板并生成
好了,接下来我们定义一个简单的模板来,并通过消费ADO.NET Data Service来绑定数据源。需要注意的是一个定义好的模板必须具有sys:attach=”dv”属性,这表明这个模板对于DataView空间来说是有效的,并且AJAX类库会在初始化过程中来关联。如果sys:attach没有被声明,在执行set_data()方法时会产生一个空引用的错误。
<div> <ul id="customerListView" class="sys-template" sys:attach="dv"> <li>{{ CompanyName }}</li> </ul> </div> |
上边一段代码实际上定义了一个名为customerListView的DataView控件—它之所以成为DataView控件是因为sys:attach=”dv”的作用。每个DataView控件具有一个set_data(dataSource)方法来render template. 我们通过执行ADO.NET Data Service查询来获取数据:
function pageLoad() { setupDataService(); queryService(); }
var dataService;
function setupDataService() { dataService = new Sys.Data.AdoNetServiceProxy("NorthwindService.svc"); dataService.set_defaultFailedCallback(onFailure); dataService.set_defaultSucceededCallback(onSuccess); }
function onSuccess(result, userContext, operation) { var dataView = $find("customerListView"); dataView.set_data(result); }
function onFailure(result, userContext, operation) { $get("errorStatus").value = result.get_message() + "\r\tStatus Code: " + result.get_statusCode() + "\r\tTimed Out: " + result.get_timedOut(); }
function queryService() { dataService.query("/Customers"); } |
通过扩展标记执行模板绑定
上边的示例代码我们定义了DataView的模板元素,并通过JavaScript代码来绑定Template并呈现数据的。AJAX类库同时提供了一项新的功能就是对声明式编程的支持。对于上边的功能我们同样可以不写 代码,直接在HTML标记中通过声明式编程来实现。以下代码片段就实现了与上边示例相同的功能:
<div> <ul id="productListView" class="sys-template" sys:attach="dv" dv:datasource="{{ new Sys.Data.AdoNetDataSource() }}" dv:serviceuri="NorthwindService.svc" dv:query="Customers?$orderby=CompanyName"> <li>{{CompanyName}}</li> </ul> </div> |
这里使用了DataSource控件,通过声明一个客户端的DataService对应的Data Source控件并执行query查询来绑定。这就类似于ObjectDataSource。对于DataView我们可以设置下边几个属性:
Property |
Description |
data |
以JSON对象或集合表示的生成模板的数据源 |
dataSource |
指定数据源控件 |
serviceUri |
Web ServiceURI |
itemTemplate |
模板定义 |
query |
Web Service的方法或者ADO.NET Data Service的URI查询串 |
selecteditemclass |
选定项目的样式类 |
class:alternateItem |
交替项的样式类 |
同时,对于某些数据你可能需要格式化,直接将格式化函数应用于数据字段本身即可:
<tr> <td>{{EmployeeID}}</td> <td>{{TitleOfCourtesy}}</td> <td>{{FirstName}} {{LastName}}</td> <td>{{Title}}</td> <td>{{formatDate(BirthDate)}}</td> <td>{{Country}}</td> <td>{{City}}</td> <td>{{Address}}</td> </tr>
…. function formatDate(value) { //return parseDate(value).localeFormat("d"); return value.format("d"); } |
创建主次视图
DataView控件可以像WPF中的Binding一样来指定两个相同的对象之间针对某个属性来进行绑定,这就相当于在两者之间共享了一个数据。这样的语法也和WPF中的Binding的语法一样,需要制定Path(虽然这是隐含的)和Source属性。
dv:data="{binding selectedData, source={{$find('CustomerListView')}}}" |
这是一项很便利的技术,使得我们可以在另外的 视图中来共享CustomerListView视图中当前选中的对象(JSON对象)来作为我们这个视图的数据源。这样,在定义好了这个视图的模板后你不用写任何对当前视图的额外代码即可实现主次视图的同步。
来看看我们对主视图和详细视图的定义:
<fieldset style="float:left"> <legend>Master View</legend> <div id="CustomerListView" sys:attach="dv" dv:itemtemplate="masterTemplate" dv:itemplaceholder="masterPh" dv:selecteditemclass="selectedItem"> <div id="masterPh"> Requesting from server side... </div> </div> <div id="masterTemplate" class="sys-template" sys:attach="dv"> <a sys:id="{{$id('cust')}}" sys:command="select">{{ContactName}}</a> <br /> </div> </fieldset> <fieldset> <legend>Detail View</legend> <div id="CustomerDetailView" sys:attach="dv" dv:data="{binding selectedData, source={{$find('CustomerListView')}}}" dv:itemtemplate="detailTemplate" dv:itemplaceholder="detailPh"> <div id="detailPh"> No deta... </div> </div> <div id="detailTemplate" class="sys-template"> Customer ID: <span id="customerId">{{CustomerID}}</span> <br /> Company Name: <input type="text" id="companyName" value="{{CompanyName}}" /> <br /> Contact Name:<input type="text" id="contactName" value="{{ContactName}}" /> <br /> Contact Title:<input type="text" id="title" value="{{ContactTitle}}" /> <br /> <input type="button" value="Update" onclick="updateCustomer();" /> </div> </fieldset> |
当主视图的选择项有所变化时,详细视图会同时发生变化并将几个数据项绑定。
我们可以顺便实现在客户端更新这些数据,其实这是对前边AJAX类库消费ADO.NET Data Service的复习。你可以很轻松的利用AdoNetService的方法来更新数据。当更新完数据后刷新主次视图:
function updateCustomer() { customerID = $get("customerId").innerHTML; dataService.query("/Customers?$filter=CustomerID eq '" + customerID + "'", ItemFound); } function ItemFound(result, userContext, operation) { if (result.length > 0) { result[0].CompanyName = $get("companyName").value; result[0].ContactName = $get("contactName").value; result[0].ContactTitle = $get("title").value; dataService.update(result[0], updateSuccessful); } } function updateSuccessful() { savedIndex = $find("CustomerListView").get_selectedIndex(); dataService.query("/Customers?$orderby=ContactName", refresh, onFailure, savedIndex); } function refresh(result, userContext, operation) { var dataView = $find("CustomerListView"); dataView.set_data(result); dataView.set_selectedIndex(userContext); } |
看起来很简单吧?最后再说说动态创建DataView吧,看看例子就明白了,其实你只需要传递Web Service的地址和要执行的方法来创建一个DataView控件,并在$create的最后一个参数中传入模板元素即可,例如我定义了如下方法:
[WebMethod] public static IEnumerable<AEmployee> GetEmployees() { return new List<AEmployee> { new AEmployee {EmployeeName = "Allan"}, new AEmployee {EmployeeName = "James"}, new AEmployee {EmployeeName = "Jason"} }; } |
在客户端定义了模板:
<div> <ul id="employeeListView" class="sys-template"> <li>{{EmployeeName}}</li> </ul> </div> |
通过以下代码即可创建对employeeListView模板的绑定:
$create( Sys.UI.DataView, { serviceUri: "Default.aspx", query: "GetEmployees" }, {}, {}, $get("employeeListView") ); |
AJAX 4.0给我们提供了很多的功能,Template只是其中的一种,另外想Timer等都给了我们更多的扩展和选择。相信不久的发布版本会让我们看到更好的东西:)