您的位置:首页 > 编程语言 > ASP

自定义ASP.NET AJAX拖放功能示例程序:实现IDragSource和IDropTarget接口将商品拖放至购物车中

2007-05-29 10:31 1411 查看
本文来自《ASP.NETAJAX程序设计——第II卷:客户端MicrosoftAJAXLibrary相关》第9章第3节。

9.3示例程序:实现IDragSourceIDropTarget接口将商品拖放至购物车中

本章第1节介绍了ASP.NETAJAX客户端拖放框架中的DragDropManager对象以及IDragSource和IDropTarget两个重要接口。下面就让我们通过一个简单但却足够完善的示例程序来说明其具体的使用方法。

9.3.1示例程序功能

本示例程序模拟了一个网上商店。程序加载之后将自动从服务器端WebService中取得当前的商品信息,并显示在页面中。同样显示在页面中的还有用户的购物车。如图9-6所示。



图9-6网上商店的初始界面

用户可以非常直观地在左侧的商品列表中用鼠标选择并将某种商品拖动到右侧的购物车中,类似于实际生活中在超市购物的场景,如图9-7所示。是不是很酷呢?



图9-7通过拖动商品到购物车中完成购物过程

在购物车范围内松开鼠标左键,商品即被添加到了购物车中。每拖放一次某商品,购物车中该商品的数量就会加1。图9-8显示了购物车中包含一本《Atlas基础教程》、两本《ASP.NETAJAX程序设计第I卷》和三本《CSS禅意花园》时的样式。



图9-8在购物车中添加多个商品

在图9-8中点击购物车中的“Order”按钮,程序将把当前购物车中的商品传回服务器端WebService中进行处理。然后把WebService的处理结果显示给用户,如图9-9所示。



图9-9用服务器端WebService实现购买功能

9.3.2编写服务器端WebService

既然程序需要从服务器端取得数据,还需要将购物车中的商品提交回服务器处理,那么处理数据的WebService定是必不可少的。首先创建一个名为ShoppingService的WebService:

[System.Web.Script.Services.ScriptService]

[code]publicclassShoppingService:System.Web.Services.WebService
{

}

[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

在其中创建一个名为Data的私有属性,表示当前网上商店中的产品集合:

privateList<Product>_products;

[code]privateList<Product>Products
{

get

{

if(_products==null)

{

_products=newList<Product>();


_products.Add(newProduct(1,"Atlas基础教程",39));

_products.Add(newProduct(2,"ASP.NETAJAX程序设计第I卷",49));

_products.Add(newProduct(3,"ASP.NETAJAX程序设计第II卷",55));

_products.Add(newProduct(4,"ASP.NETAJAX程序设计第III卷",39));

_products.Add(newProduct(5,"CSS禅意花园",49));

}

return_products;

}

}

[/code]
出于演示的目的,我们并没有查询数据库得到商品集合,而是直接硬编码了几种商品(这些商品都是我已经出版或即将要出版的图书)。在实际开发中,这部分数据通常都需要查询数据库得到。

上述代码中用到的Product类表示一种商品,其定义如下。Id、Name和Price属性分别代表商品的ID、名称和价格:


publicclassProduct

[code]{
privateint_id;

publicintId

{

get{return_id;}

set{_id=value;}

}


privatestring_name;

publicstringName

{

get{return_name;}

set{_name=value;}

}


privateint_price;

publicintPrice

{

get{return_price;}

set{_price=value;}

}


publicProduct()

{

}


publicProduct(intid,stringname,intprice)

{

this._id=id;

this._name=name;

this._price=price;

}

}

[/code]
回到ShoppingService这个WebService中。编写一个名为GetProducts()的方法,用来返回现有的商品:

[WebMethod]

[code]publicProduct[]GetProducts()
{

returnProducts.ToArray();

}

[/code]
还需要一个名为Order()的方法,用来处理客户端提交回的购物车中商品的信息,并返回处理结果。注意Order()的方法的参数类型为Dictionary<string,int>,其中每个条目的Key为该商品的Id,Value为购物车中该商品的个数:

[WebMethod]

[code]publicstringOrder(Dictionary<string,int>productsToBeOrdered)
{

//商品总数

inttotalQuantity=0;


//商品总价格

inttotalPrice=0;


//计算商品总数及商品总价格

foreach(KeyValuePair<string,int>productQuantityinproductsToBeOrdered)

{

foreach(ProductproductinProducts)

{

if(product.Id.ToString()==productQuantity.Key)

{

totalQuantity+=productQuantity.Value;

totalPrice+=(product.Price*productQuantity.Value);

break;

}

}

}


//进行其他处理

//......


//返回客户端处理结果

returnstring.Format(

"You'veordered{0}product(s)andthetotalpriceis{1}.Thankyou!",

totalQuantity,

totalPrice

);

}

[/code]
这样即完成了服务器端WebService的编写。

9.3.3编写DraggableProductBehavior实现可拖动的商品

接下来定义一个名为DraggableProductBehavior的行为,该行为将实现Sys.Preview.UI.IDragSource接口,用来附加到表示产品的DOM元素上并为其提供拖动支持。

新建一个名为ShoppingCart.js的JavaScript文件,先来注册Dflying命名空间:

Type.registerNamespace("Dflying");


然后声明该DraggableProductBehavior的实例字段:


Dflying.DraggableProductBehavior=function(element){

[code]//初始化基类
Dflying.DraggableProductBehavior.initializeBase(this,[element]);


//按下鼠标键时的事件处理函数

this._mouseDownHandler=Function.createDelegate(this,this._handleMouseDown);


//该可拖动对象所表示的产品

this._product=null;


//拖动时跟随鼠标的半透明元素

this._visual=null;

}

[/code]
接下来是DraggableProductBehavior的原型定义。篇幅所限,这里不能对代码进行详细解释,请参考其中的注释仔细阅读。需要特别留意的是IDragSource接口中各个方法的实现方式,以及其中粗体部分告知DragDropManager开始拖放操作的语法:


Dflying.DraggableProductBehavior.prototype={

[code]//IDragSource接口中的方法
//取得该可拖动对象的数据类型——"Product"

get_dragDataType:function(){

return"Product";

},


//取得该可拖动对象的数据

getDragData:function(context){

returnthis._product;

},


//可拖动对象的拖拽模式——拷贝

get_dragMode:function(){

returnSys.Preview.UI.DragMode.Copy;

},


//拖动开始时的处理方法

onDragStart:function(){

},


//拖动进行时的处理方法

onDrag:function(){

},


//拖动结束时的处理方法

onDragEnd:function(canceled){

if(this._visual)

this.get_element().parentNode.removeChild(this._visual);

},


//product属性

get_product:function(product){

returnthis._product;

},


set_product:function(product){

this._product=product;

},


//初始化方法

initialize:function(){

$addHandler(this.get_element(),"mousedown",this._mouseDownHandler);

},


//mousedown事件处理函数

_handleMouseDown:function(ev){

//DragDropManager需要该项设定

window._event=ev;


//设置拖动时跟随鼠标的半透明元素的样式

this._visual=this.get_element().cloneNode(true);

this._visual.style.opacity="0.7";

this._visual.style.filter=

"progid:DXImageTransform.Microsoft.BasicImage(opacity=0.7)";

this._visual.style.zIndex=99999;

this.get_element().parentNode.appendChild(this._visual);

varlocation=Sys.UI.DomElement.getLocation(this.get_element());

Sys.UI.DomElement.setLocation(this._visual,location.x,location.y);


//告知DragDropManager开始拖放操作

Sys.Preview.UI.DragDropManager.startDragDrop(this,this._visual,null);

},


//析构方法

dispose:function(){

if(this._mouseDownHandler)

$removeHandler(this.get_element(),"mousedown",this._mouseDownHandler);

this._mouseDownHandler=null;


Dflying.DraggableProductBehavior.callBaseMethod(this,'dispose');

}

}

[/code]
最后在ASP.NETAJAX客户端框架中注册该DraggableProductBehavior行为。可以看到该行为实现了IDragSource接口:

Dflying.DraggableProductBehavior.registerClass(

[code]"Dflying.DraggableProductBehavior",
Sys.UI.Behavior,

Sys.Preview.UI.IDragSource

);

[/code]

9.3.4编写ShoppingCartBehavior实现可接受商品投放的购物车

依然在ShoppingCart.js这个JavaScript文件中,我们还要定义一个名为ShoppingCartBehavior的行为,该行为将实现Sys.Preview.UI.IDropTarget接口,用来附加到表示购物车的DOM元素上并让其能够接受可拖动对象的投放。

首先声明该ShoppingCartBehavior的实例字段:


Dflying.ShoppingCartBehavior=function(element){

[code]//初始化基类
Dflying.ShoppingCartBehavior.initializeBase(this,[element]);


//购物车中的产品列表

this._products=newObject();

}

[/code]
接下来是ShoppingCartBehavior的原型定义。同样限于篇幅,这里不一一详细说明。请注意代码中IDropTarget接口中各个方法的实现方式,以及其中粗体部分在DragDropManager中注册/取消注册该投放目标对象的语法:


Dflying.ShoppingCartBehavior.prototype={

[code]//IDropTarget接口中的方法
//返回购物车元素

get_dropTargetElement:function(){

returnthis.get_element();

},


//判断某可拖动元素是否能够投放在该投放目标对象中

canDrop:function(dragMode,dataType,data){

return(dataType=="Product"&&data);

},


//将某可拖动元素投放在该投放目标对象中

drop:function(dragMode,dataType,data){

if(dataType=="Product"&&data){

//购物车中尚无本产品,设置数量为1

if(this._products[data.Id]==null){

this._products[data.Id]={Product:data,Quantity:1};

}

//购物车中已经有本产品,将其数量加1

else{

this._products[data.Id].Quantity++;

}


//刷新购物车的UI

this._refreshShoppingCart();


//将购物车背景颜色设置回白色

this.get_element().style.backgroundColor="#fff";

}

},


//某可拖动元素位于该投放目标对象中时的处理方法

onDragEnterTarget:function(dragMode,dataType,data){

if(dataType=="Product"&&data){

//设置购物车的背景颜色为灰色

this.get_element().style.backgroundColor="#E0E0E0";

}

},


//某可拖动元素离开该投放目标对象时的处理方法

onDragLeaveTarget:function(dragMode,dataType,data){

if(dataType=="Product"&&data){

//将购物车背景颜色设置回白色

this.get_element().style.backgroundColor="#fff";

}

},


//某可拖动元素在该投放目标对象中拖动时的处理方法

onDragInTarget:function(dragMode,dataType,data){

},


//根据当前购物车中的产品列表刷新购物车的UI

_refreshShoppingCart:function(){

varcartBuilder=newSys.StringBuilder();

for(varidinthis._products){

cartBuilder.append("<div>");

cartBuilder.append(this._products[id].Product.Name);

cartBuilder.append("*");

cartBuilder.append(this._products[id].Quantity);

cartBuilder.append("</div>");

}


this.get_element().innerHTML=cartBuilder.toString();

},


//返回表示当前购物车中的产品Id以及数量的对象

getProductsToBeOrdered:function(){

varproductsToBeOrdered=newObject();


for(varidinthis._products){

productsToBeOrdered[id]=this._products[id].Quantity;

}


returnproductsToBeOrdered;

},


//初始化方法

initialize:function(){

//初始化基类

Dflying.ShoppingCartBehavior.callBaseMethod(this,"initialize");


//在DragDropManager中注册该投放目标对象

Sys.Preview.UI.DragDropManager.registerDropTarget(this);

},


//析构方法

dispose:function(){

//在DragDropManager中取消注册该投放目标对象

Sys.Preview.UI.DragDropManager.unregisterDropTarget(this);


Dflying.ShoppingCartBehavior.callBaseMethod(this,"dispose");

}

}

[/code]
最后在ASP.NETAJAX客户端框架中注册该ShoppingCartBehavior行为。可以看到该行为实现了IDropTarget接口:

Dflying.ShoppingCartBehavior.registerClass("Dflying.ShoppingCartBehavior",

[code]Sys.UI.Behavior,Sys.Preview.UI.IDropTarget);
[/code]
在ShoppingCart.js文件的末尾,不要忘记调用Application对象的notifyScriptLoaded()方法,通知ASP.NETAJAX客户端框架该脚本文件已经顺利加载:

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();



9.3.5编写页面代码

新建一个ASP.NET页面,在其中添加一个ScriptManager控件并引入必要的脚本文件(PreviewScript.js、PreviewDragDrop.js和ShoppingCart.js)以及9.3.2节中编写的WebService:


<asp:ScriptManagerID="sm"runat="server">

[code]<Scripts>
<asp:ScriptReferenceAssembly="Microsoft.Web.Preview"

Name="PreviewScript.js"/>

<asp:ScriptReferenceAssembly="Microsoft.Web.Preview"

Name="PreviewDragDrop.js"/>

<asp:ScriptReferencePath="ShoppingCart.js"/>

</Scripts>

<Services>

<asp:ServiceReferencePath="ShoppingService.asmx"/>

</Services>

</asp:ScriptManager>

[/code]
然后编写购物车的相关HTML。其中id为shoppingCart的<div/>表示购物车元素。id为btnOrder的<input/>表示提交订单的按钮:


<divid="shoppingCartContainer">

[code]<div><strong>ShoppingCart</strong></div>
<divid="shoppingCart">DropProductsHere...</div>

<inputid="btnOrder"type="button"value="Order"

onclick="returnbtnOrder_onclick()"/>

</div>

[/code]
网站中产品,即可拖动元素的容器相关的HTML非常简单——一个<div/>而已。随后我们将在程序运行时根据WebService返回的商品集合动态创建容器中的各个表示商品的元素:


<h1>Dflying'sBooks</h1>

[code]<divid="productContainer"></div>
[/code]
示例程序中购物车和商品列表相关的CSSClass定义如下:

#shoppingCartContainer

[code]{
float:right;

width:220px;

border:1pxsolidblack;

margin:3px;

}

#productContainerdiv

{

width:250px;

padding:3px;

margin:3px;

border:1pxsolid#666;

background-color:#fff;

cursor:move;

}

[/code]

9.3.6通过WebService取得商品并显示在页面中

在客户端应用程序初始化之后,我们需要异步调用服务器端WebService得到商店中产品的信息,并顺便为购物车添加ShoppingCartBehavior行为:


functionpageLoad(sender,args){

[code]//调用WebService得到商店中的产品集合
ShoppingService.GetProducts(onProductsGot);


//为购物车添加ShoppingCartBehavior行为

$create(

Dflying.ShoppingCartBehavior,

{"name":"myShoppingCartBehavior"},

null,

null,

$get("shoppingCart")

);

}

[/code]
在onProductsGot()回调函数中,我们要根据返回的商品集合动态创建容器中的各个表示商品的元素,并为其一一添加DraggableProductBehavior行为:


functiononProductsGot(result){

[code]//获取显示各个产品的容器
varproductContainer=$get("productContainer");


//遍历服务器端返回的产品集合

for(varindex=0;index<result.length;++index){

//当前产品

varthisProduct=result[index];


//根据该产品信息创建DOM元素,并添加到产品容器中

varproductElem=document.createElement("div");

productElem.innerHTML=thisProduct.Name+"-RMB:"

+thisProduct.Price;

productContainer.appendChild(productElem);


//为该产品添加DraggableProductBehavior行为

$create(

Dflying.DraggableProductBehavior,

{"product":thisProduct},//设置product属性

null,

null,

productElem

);

}

}

[/code]

9.3.7将购物车中的商品提交回WebService处理

当用户点击购物车中的“Order”按钮时,我们需要把购物车中当前的产品信息(包括Id和数量)传回服务器端进行处理。

“Order”按钮的click事件的处理函数如下。其中首先使用Sys.UI.Behavior.getBehaviorByName()方法得到购物车所附加的ShoppingCartBehavior行为,然后取得当前购物车中各个产品的Id和数量,最后将这部分信息回传给WebService进行处理:


functionbtnOrder_onclick(){

[code]//得到购物车所附加的ShoppingCartBehavior行为
varshoppingCartBehavior=Sys.UI.Behavior.getBehaviorByName(

$get("shoppingCart"),

"myShoppingCartBehavior"

);


//取得当前购物车中各个产品的Id和数量

varproductsToBeOrdered=

shoppingCartBehavior.getProductsToBeOrdered();


//调用WebService处理订单

ShoppingService.Order(productsToBeOrdered,onOrdered);

}

[/code]
在productsToBeOrdered()回调函数中,我们只是简单地使用alert()方法将服务器端的响应提示给用户:


functiononOrdered(result){

[code]alert(result);
}

[/code]

这样即完成了本示例程序的编写。运行该程序并尝试用这种崭新的拖放方式进行购物,你将看到如图9-6、图9-7、图9-8和图9-9中所示的界面。这种简单直观的购物体验是不是很令人赞叹呢?

在本示例程序中,我们完整地演示了ASP.NETAJAX客户端拖放框架支持的自定义拖放效果的强大功能,以及IDragSource和IDropTarget两个重要接口在拖放全过程中提供的完善的可定制能力。在实际应用中,我们完全可以简单地通过实现这两个接口来实现那些用户梦寐以求的炫目的拖放效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐