在Ajax程序中实现传统桌面程序中异常简单的拖放功能却并不是件容易的事情。然而Web上的拖放功能又如此的让人痴迷,所以几乎每个成熟的Ajax类库都提供了自己的一套实现拖放的封装,ASP.NET AJAX (Atlas) 自然也不例外。本文将总结并简要分析ASP.NET AJAX (Atlas) 中拖放功能的6种不同的实现方法,希望能够帮助朋友们选出最适合实际需求的方法。
其中第1到第4种方案,在我的《ASP.NET Ajax程序设计——第I卷:服务器端ASP.NET 2.0 AJAX Extensions与ASP.NET AJAX Control Toolkit》一书中有详细介绍(4月出版),本文中的代码和图示也节选自该书。第5第6种方案,在我的《ASP.NET 2.0 Ajax程序设计——第II卷:客户端Microsoft AJAX Library》一书中将有详细介绍(暂定7月出版)。
不过纵观这些解决方案,我很遗憾的发现,要么是使用简单,可定制能力差,要么就是可定制能力强,但使用起来要写很多代码。希望ASP.NET AJAX (Atlas) 团队能够再接再厉,努力把这个重要功能做得更好。或者我有哪种方法漏掉了,也请朋友们帮忙补充一下。
[1] 使用服务器端DragOverlayExtender或客户端DragOverlayBehavior
服务器端的DragOverlayExtender就是靠着客户端DragOverlayBehavior而实现的,前者是后者在服务器端的组件化封装,所以我们将二者放在一起讨论。
这个“拖放”功能很简单,其实这只是个“拖拽”,而没有“投放”。也就是说,你可以随意将某个Panel在页面中拖来拖去,不过却没有什么固定的地方可以“投放”,就像在Windows桌面上拖放某个窗口的位置一样——其实用处不大,也没有提供什么可定制能力。但它使用起来非常简单,也支持将Panel的位置保存在Profile中。
下面是一段DragOverlayExtender的示例代码,至于DragOverlayBehavior的用法,请查看DragOverlayExtender页面生成的HTML代码:
<asp:Login ID="floatLogin" BackColor="white"
BorderStyle="Solid" BorderColor="black"
runat="server">
</asp:Login>
<asp:DragOverlayExtender ID="DragOverlayExtender2"
Enabled="true" TargetControlID="floatLogin"
runat="server" />
效果如下:
[2] 使用服务器端DragPanel
DragPanel是ASP.NET AJAX Control Toolkit中的一个扩展器控件。其功能基本与DragOverlayExtender和DragOverlayBehavior一样,且同样可以保存Panel的位置信息至Profile中。不同之处在于,DragOverlayExtender和DragOverlayBehavior的拖拽实现方式中,鼠标放在整个Panel的任何部分都可以开始拖拽,而DragPanel在进行拖拽时,只有鼠标放在指定的DragHandle(类似于Windows窗口的标题栏部分)中才能开始拖拽。
对于DragHandle的扩展性和实用性,同样不敢恭维。
下面是一段示例代码:
<asp:Panel ID="floatPanel" CssClass="floatPanel" runat="server">
<asp:Panel ID="floatPanelHandle" CssClass="handle" runat="server">
窗口的拖动
</asp:Panel>
<div class="content">
在Windows中,对窗口的拖动似乎成了我们习以为常的事情。
………………
………………
Window窗口的表现行为一样。
</div>
</asp:Panel>
<ajaxToolkit:DragPanelExtender ID="dpe" TargetControlID="floatPanel"
DragHandleID="floatPanelHandle" runat="server">
</ajaxToolkit:DragPanelExtender>
效果如下:
[3] 使用服务器端ReorderList
ASP.NET AJAX Control Toolkit中的ReorderList控件将在页面中呈现出一个由数据绑定自动生成的条目列表。用户可以通过鼠标拖动某一项来直接改变该列表中条目彼此之间的相对位置关系,且在拖动的过程中,ReorderList控件提供了丰富的、可定制的视觉效果。当用户在某个位置放开鼠标之后,ReorderList控件也将同样会自动通知与其绑定的数据源控件,以Ajax的异步或整页回送的同步方式更新服务器端数据。
ReorderList控件的使用比较简单(服务器端控件),功能也相当的丰富,扩展能力也不错。不过仍称不上最灵活,比如我们想把条目在多个ReorderList之间拖放,那么就没办法实现了——因此,不要指望它能实现WebPart那样的功能。
详细介绍请参考:《使用ASP.NET AJAX Control Toolkit中的ReorderList控件实现用鼠标拖动改变条目顺序》
下面是一段示例代码:
<ajaxToolkit:ReorderList ID="musicList" CssClass="musicList"
DragHandleAlignment="Left" PostBackOnReorder="false"
DataSourceID="musicDataSource" DataKeyField="Id"
SortOrderField="Order" runat="server">
<ItemTemplate>
<ajaxToolkit:Rating ID="rating" runat="server"
CssClass="rating" StarCssClass="ratingStar"
FilledStarCssClass="filledRatingStar" EmptyStarCssClass="emptyRatingStar"
CurrentRating='<%# Bind("Rating") %>' MaxRating="5"
ReadOnly="true">
</ajaxToolkit:Rating>
</ItemTemplate>
<ReorderTemplate>
<div class="dragDue">
Drop Here!
</div>
</ReorderTemplate>
<DragHandleTemplate>
<asp:Label ID="lbTitle" CssClass="dragHandle"
ToolTip="Drag Me!" runat="server" Text='<%# Bind("Name") %>'>
</asp:Label>
</DragHandleTemplate>
</ajaxToolkit:ReorderList>
效果挺酷的:
[4] 使用UpdatePanel与ASP.NET AJAX中的新版本WebPart控件
ASP.NET 2.0中的WebPart相关的控件虽然非常丰富,易于使用且功能强大,我们在程序中也很需要它所提供的拖拽功能,但它却存在着两个致命的缺陷:
- 拖放功能只支持IE浏览器。
- 每次用户通过拖放改变配件的位置之后,页面总会自动进行回送以保存当前的设定。
其中第一个问题可以通过ASP.NET AJAX中的新版本WebPart控件搞定,第二个问题可以通过添加UpdatePanel搞定,本来在CTP版本中的ASP.NET AJAX里面,这些功能均已经完美实现了。谁知道在最新的Futures CTP中,却又不好用了。
既然现在已经不能用了,也就没必要分析其优点缺点了。不过还是给出一张截图吧,缅怀一下曾经的辉煌(注意,这可是在Firefox中啊!)……
[5] 使用客户端DragDropList
DragDropList定义于ASP.NET AJAX Futures CTP中,功能非常强大,且全部在客户端实现,给服务器端减轻了不少的压力。使用DragDropList实现第4种解决方案中的WebPart类似的效果完全没有问题,不过唯一让人感到遗憾的就是,其扩展功能不是很好,用户虽然可以随便将某个Panel从一个区域拖到另一个区域,但拖拽的结果却很难持久化下来……且使用起来也不是那么的容易,效率上更是不敢恭维……总之,这是个很让人矛盾的东西,有些鸡肋的感觉。
我曾经在《使用ASP.NET Atlas实现拖放(Drag & Drop)效果(下)》这篇文章中给出过DragDropList的示例程序,虽然是基于CTP版本的ASP.NET AJAX ,不过实际上并不需要多少修改就能运行于最新版本之上。感兴趣的朋友可以看看,也可以到官方论坛上搜索一下相关的主题。
[6] 在客户端自行实现IDragSource和IDropTarget接口
来到了这个解决方案,可以说你对ASP.NET AJAX中的拖拽实现有了一个较深入的了解。上面的DragDropList其实就是实现了IDragSource和IDropTarget接口,其中前者用来定义可以被拖拽的项目,后者用来定义可以被投放的区域。详细理论上的说明,可以参考我的文章《使用ASP.NET Atlas实现拖放(Drag & Drop)效果(上)》,虽然目前已经有所变化,不过仍可以参考。
这种实现方案应该说是最为强大的了,想要什么功能,肯定都能实现。不过实际开发中的难度也不小——甚至可以说是相当复杂,Jeff Prosise的这篇文章《Implementing Drag-Drop in ASP.NET AJAX》给出了一个非常简单的示例程序,感兴趣想要学习的朋友不妨看看……