本文来自《ASP.NET AJAX程序设计——第II卷:客户端Microsoft AJAX Library相关》第9章第3节。

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

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

9.3.1 示例程序功能

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

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

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

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

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

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

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

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

9.3.2 编写服务器端Web Service

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

[System.Web.Script.Services.ScriptService]
public class ShoppingService : System.Web.Services.WebService
{
}

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

private List<Product> _products;
private List<Product> Products
{
    get
    {
        if (_products == null)
        {
            _products = new List<Product>();
 
            _products.Add(new Product(1, "Atlas基础教程", 39));
            _products.Add(new Product(2, "ASP.NET AJAX程序设计第I卷", 49));
            _products.Add(new Product(3, "ASP.NET AJAX程序设计第II卷", 55));
            _products.Add(new Product(4, "ASP.NET AJAX程序设计第III卷", 39));
            _products.Add(new Product(5, "CSS禅意花园", 49));
        }
        return _products;
    }
}

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

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

public class Product
{
    private int _id;
    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }
    
    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
    
    private int _price;
    public int Price
    {
        get { return _price; }
        set { _price = value; }
    }
    
    public Product()
    {
    }
 
    public Product(int id, string name, int price)
    {
        this._id = id;
        this._name = name;
        this._price = price;
    }
}

回到ShoppingService这个Web Service中。编写一个名为GetProducts()的方法,用来返回现有的商品:

[WebMethod]
public Product[] GetProducts()
{
    return Products.ToArray();
}

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

[WebMethod]
public string Order(Dictionary<string, int> productsToBeOrdered)
{
    // 商品总数
    int totalQuantity = 0;
    
    // 商品总价格
    int totalPrice = 0;
 
    // 计算商品总数及商品总价格
    foreach (KeyValuePair<string, int> productQuantity in productsToBeOrdered)
    {
        foreach (Product product in Products)
        {
            if (product.Id.ToString() == productQuantity.Key)
            {
                totalQuantity += productQuantity.Value;
                totalPrice += (product.Price * productQuantity.Value);
                break;
            }
        }
    }
    
    // 进行其他处理
    // ......
 
    // 返回客户端处理结果
    return string.Format(
        "You've ordered {0} product(s) and the total price is {1}. Thank you!",
        totalQuantity,
        totalPrice
    );
}

这样即完成了服务器端Web Service的编写。

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

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

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

Type.registerNamespace("Dflying");

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

Dflying.DraggableProductBehavior = function(element) {
    // 初始化基类
    Dflying.DraggableProductBehavior.initializeBase(this, [element]);
    
    // 按下鼠标键时的事件处理函数
    this._mouseDownHandler = Function.createDelegate(this, this._handleMouseDown);
    
    // 该可拖动对象所表示的产品
    this._product = null;
    
    // 拖动时跟随鼠标的半透明元素
    this._visual = null;
}

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

Dflying.DraggableProductBehavior.prototype = {
    // IDragSource接口中的方法
    // 取得该可拖动对象的数据类型——"Product"
    get_dragDataType: function() {
        return "Product";
    },
 
    // 取得该可拖动对象的数据
    getDragData: function(context) {
        return this._product;
    },
 
    // 可拖动对象的拖拽模式——拷贝
    get_dragMode: function() {
        return Sys.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) {
        return this._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);
        var location = 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');
    }
}

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

Dflying.DraggableProductBehavior.registerClass(
    "Dflying.DraggableProductBehavior",
    Sys.UI.Behavior, 
    Sys.Preview.UI.IDragSource
);

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

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

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

Dflying.ShoppingCartBehavior = function(element) {
    // 初始化基类
    Dflying.ShoppingCartBehavior.initializeBase(this, [element]);
    
    // 购物车中的产品列表
    this._products = new Object();
}

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

Dflying.ShoppingCartBehavior.prototype = {
    // IDropTarget接口中的方法
    // 返回购物车元素
    get_dropTargetElement: function() {
        return this.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() {
        var cartBuilder = new Sys.StringBuilder();
        for (var id in this._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() {
        var productsToBeOrdered = new Object();
        
        for (var id in this._products) {
            productsToBeOrdered[id] = this._products[id].Quantity;
        }
        
        return productsToBeOrdered;
    },
    
    // 初始化方法
    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");
    }
}

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

Dflying.ShoppingCartBehavior.registerClass("Dflying.ShoppingCartBehavior",
    Sys.UI.Behavior, Sys.Preview.UI.IDropTarget);

在ShoppingCart.js文件的末尾,不要忘记调用Application对象的notifyScriptLoaded()方法,通知ASP.NET AJAX客户端框架该脚本文件已经顺利加载:

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

9.3.5 编写页面代码

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

<asp:ScriptManager ID="sm" runat="server">
    <Scripts>
        <asp:ScriptReference Assembly="Microsoft.Web.Preview" 
            Name="PreviewScript.js" />
        <asp:ScriptReference Assembly="Microsoft.Web.Preview" 
            Name="PreviewDragDrop.js" />
        <asp:ScriptReference Path="ShoppingCart.js" />
    </Scripts>
    <Services>
        <asp:ServiceReference Path="ShoppingService.asmx" />
    </Services>
</asp:ScriptManager>

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

<div id="shoppingCartContainer">
    <div><strong>Shopping Cart</strong></div>
    <div id="shoppingCart">Drop Products Here...</div>
    <input id="btnOrder" type="button" value="Order" 
        onclick="return btnOrder_onclick()" />
</div>

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

<h1>Dflying's Books</h1>
<div id="productContainer"></div>

示例程序中购物车和商品列表相关的CSS Class定义如下:

#shoppingCartContainer
{
    float: right; 
    width: 220px; 
    border: 1px solid black;
    margin: 3px;
}
#productContainer div
{
    width: 250px;
    padding: 3px;
    margin: 3px;
    border: 1px solid #666;
    background-color: #fff;
    cursor: move;
}

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

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

function pageLoad(sender, args) {
    // 调用Web Service得到商店中的产品集合
    ShoppingService.GetProducts(onProductsGot);
    
    // 为购物车添加ShoppingCartBehavior行为
    $create(
        Dflying.ShoppingCartBehavior, 
        {"name": "myShoppingCartBehavior"},
        null, 
        null, 
        $get("shoppingCart")
    );
}

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

function onProductsGot(result) {
    // 获取显示各个产品的容器
    var productContainer = $get("productContainer");
    
    // 遍历服务器端返回的产品集合
    for (var index = 0; index < result.length; ++ index) {
        // 当前产品
        var thisProduct = result[index];
        
        // 根据该产品信息创建DOM元素,并添加到产品容器中
        var productElem = document.createElement("div");
        productElem.innerHTML = thisProduct.Name + " - RMB: "
            + thisProduct.Price;
        productContainer.appendChild(productElem);
        
        // 为该产品添加DraggableProductBehavior行为
        $create(
            Dflying.DraggableProductBehavior, 
            {"product": thisProduct}, // 设置product属性
            null, 
            null, 
            productElem
        );
    }
}

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

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

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

function btnOrder_onclick() {
    // 得到购物车所附加的ShoppingCartBehavior行为
    var shoppingCartBehavior = Sys.UI.Behavior.getBehaviorByName(
        $get("shoppingCart"), 
        "myShoppingCartBehavior"
    );
    
    // 取得当前购物车中各个产品的Id和数量
    var productsToBeOrdered = 
        shoppingCartBehavior.getProductsToBeOrdered();
    
    // 调用Web Service处理订单
    ShoppingService.Order(productsToBeOrdered, onOrdered);
}

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

function onOrdered(result) {
    alert(result);
}

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

在本示例程序中,我们完整地演示了ASP.NET AJAX客户端拖放框架支持的自定义拖放效果的强大功能,以及IDragSource和IDropTarget两个重要接口在拖放全过程中提供的完善的可定制能力。在实际应用中,我们完全可以简单地通过实现这两个接口来实现那些用户梦寐以求的炫目的拖放效果。

本贴子以“现状”提供且没有任何担保,同时也没有授予任何权利
This posting is provided "AS IS" with no warranties, and confers no rights.

posted on 2007-05-29 10:31 Dflying Chen 阅读(756) 评论(11)  编辑 收藏 引用 网摘 所属分类: ASP.NET AJAX (Atlas)

转载于:https://www.cnblogs.com/hzuIT/articles/764137.html

ASP.NET AJAX示例程序:实现IDragSource和IDropTarget接口将商品拖放至购物车中相关推荐

  1. 和ASP.NET AJAX应用程序环游地球

    By Guy Smith-Ferrier 本文讨论: ASP.NET AJAX 的全球支持 需要对 JavaScript 的支持 基于程序集的 AJAX 本地化 基于文件的 AJAX 本地化 本文使用 ...

  2. 微信小程序页面在调取到接口数据之前是加载中状态

    首先,我们先建一个文件夹,文件目录如下: wxml代码如下: <template name="loading"><view class="loading ...

  3. 《ASP.NET AJAX程序设计——第II卷:客户端Microsoft AJAX Library相关》定稿+详细章节列表...

    篇幅和第I卷相仿,内容则专注于客户端相关部分.该书现已定稿,正处于出版过程中.下面是详细的章节目录,我也会尽快和出版社.相关网站等沟通,开放试读: 第0章 客户端与服务器端编程模型 0.1 将表现层逻 ...

  4. 《ASP.NET AJAX程序设计——第II卷:客户端Microsoft AJAX Library相关》前言

    章节列表:http://www.cnblogs.com/dflying/archive/2007/05/18/751741.html 在最近的一年以及今后的三五年内,我们有理由相信Web应用程序将受到 ...

  5. 《ASP.NET AJAX程序设计——第II卷:客户端Microsoft AJAX Library与异步通讯层》前言...

    在最近的一年以及今后的三五年内,我们有理由相信Web应用程序将受到更多开发者和用户的青睐.作为领路人Google的一系列基于Web的产品完全地颠覆了传统的网页概念,让用户甚至不敢相信基于浏览器的程序竟 ...

  6. ASP.NET AJAX (Atlas) 拖放(Drag Drop)功能6种实现方法总结

    在Ajax程序中实现传统桌面程序中异常简单的拖放功能却并不是件容易的事情.然而Web上的拖放功能又如此的让人痴迷,所以几乎每个成熟的Ajax类库都提供了自己的一套实现拖放的封装,ASP.NET AJA ...

  7. [转载]超酷代码-使用 ASP.NET AJAX 进行拖放

    原文地址 http://msdn.microsoft.com/msdnmag/issues/08/01/WickedCode/default.aspx?loc=zh AJAX 是对 Web 用户界面的 ...

  8. ASP.NET AJAX环境的简单构建(ZT)

    1 概述 Microsoft ASP.NET AJAX 是 Microsoft 公司对 Ajax 技术的完美封装.它能使你已快速的创建包含丰富用户体验的用户界面的 Web 页面,提供加入了跨浏览器的 ...

  9. 初学 ASP.NET AJAX (一):构建 ASP.NET AJAX 开发环境

    1 概述 Microsoft ASP.NET AJAX 是 Microsoft 公司对 Ajax 技术的完美封装.它能使你已快速的创建包含丰富用户体验的用户界面的 Web 页面,提供加入了跨浏览器的 ...

最新文章

  1. Java调用cmd命令 打开一个站点
  2. Spring Security3.1登陆验证
  3. Qt Designer提升控件
  4. mysql %用户域_MySQL运维---用户权限及管理
  5. 最简单java设计模式:工厂方法模式
  6. ssrs报表服务器数据库配置文件,创建报表服务器数据库(SSRS 配置管理器)
  7. freemind在ubuntu20.04下面的安装
  8. check mk mysql_Mysql管理必备工具Maatkit详解之四(mk-duplicate-key-checker)
  9. 2020年计算机二级access考试大纲,2020年全国计算机二级ACCESS考试分析与小结(7页)-原创力文档...
  10. LTT (Linux Trace Toolkit) 简介
  11. kafka 0.8.2版本配置选项翻译
  12. Atitit 各种设计图纸分类 目录 1. Atitit 常见软件设计图纸总结 2 1.1. Uml系列图纸 2 1.2. Er图 req需求图 2 1.3. Parametric diagr
  13. memset与bzero初始化
  14. 程序员入门:三本必看的书
  15. figtree需要在JAVA下运行吗_用一个Java程序出问题了
  16. Vaa3d_DIADEM metric基本介绍_SWC拓扑结构量纲
  17. python中空集怎么表示
  18. ssl1653数字游戏
  19. ios网易大白Crash自动防护
  20. Linux系统如何替换新硬盘

热门文章

  1. as无效 mysql_MySQL 全文索引实现简单版搜索引擎
  2. 2021年春季学期-信号与系统-第十次作业参考答案-第六小题
  3. 测试半桥电路 TPS28225,NCP3420驱动MOS半桥
  4. 可以预防新冠病毒的项链 -脉动
  5. 广义互相关计算TDOA
  6. 无引脚表贴元器件焊接
  7. @Slf4j注解介绍
  8. java null布局_Java Swing 绝对布局管理方法,null布局
  9. android如何暂停倒计时,在Android中暂停和恢复倒计时器和进度条?
  10. php调用系统浏览器代码,php判断操作系统或浏览器实现代码