|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis tutorial is intended to help readers understand how certain aspects of Microsoft's new AJAX Extensions technology works. AJAX Extensions is intended to simplify the development of AJAX-style functionality. As with all technologies, however, to use a tool well, it is important to understand the underlying technology that Atlas abstracts. One of the key ASP.NET AJAX abstractions is the new XML markup syntax developed to make coding with AJAX easier (originally included with the core Atlas files, XML markup is now a part of the CTP called AJAX Futures). With XML markup, developers can modify their code declaratively. However, there are times when a developer may want to be able to change her code programmatically, and in order to accomplish this, she will need to understand that underneath the markup abstraction, she is actually dealing with good 'ol JavaScript and some custom JavaScript libraries developed by Microsoft. In order to demonstrate the relationship between the Atlas declarative model and the programmatic model, I will go through a series of examples in which the same task will be accomplished both declaratively and programmatically. I will be demonstrating how to use the PreviewDragDrop library file to perform basic drag-drop operations as well as setting up drop zones. BackgroundAs I write this, Microsoft has made some important changes to ASP.NET AJAX for the Beta 2 that have the unfortunate side-effect of breaking most of the original Atlas implementation, and has required a bit of rework of the original samples. These revised examples apply to the Beta 2 of ASP.NET AJAX. Future releases of AJAX Extensions may affect the accuracy of this tutorial. I will attempt to update the code as new versions of AJAX Extensions become available. AJAX Extensions works with .NET 2.0, and will work with Orcas when it is released. I. Declarative Drag DropThe first task is to use XML markup to add drag-drop behavior to a <system.web>
<pages>
<controls>
<add tagPrefix="asp" namespace="Microsoft.Web.UI"
assembly="Microsoft.Web.Extensions, Version=1.0.61025.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add tagPrefix="asp" namespace="Microsoft.Web.UI.Controls"
assembly="Microsoft.Web.Extensions, Version=1.0.61025.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add tagPrefix="asp" namespace="Microsoft.Web.Preview.UI"
assembly="Microsoft.Web.Preview" />
</controls>
</pages>
</system.web>
You will need to add an Atlas Script Manager control to your .aspx page and configure it to use the PreviewDragDrop library file: <asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js" />
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js" />
</Scripts>
</asp:ScriptManager>
Add the <div style="background-color:Red;height:800px;width:600px;">
<div id="draggableDiv"
style="height:100px;width:100px;background-color:Blue;">
<div id="handleBar"
style="height:20px;width:auto;background-color:Green;">
</div>
</div>
</div>
Finally, add the markup script that will make your <script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<control id="draggableDiv">
<behaviors>
<floatingBehavior handle="handleBar"/>
</behaviors>
</control>
</components>
</page>
</script>
And with that, you should have a draggable II. Imperative Drag DropTo accomplish the same thing using a programmatic model requires a bit more code, but not much more. It is important to understand that when you add an AJAX Extensions Script Manager component to your page, you are actually giving instructions to have the AJAX Extensions JavaScript library loaded into your page. The AJAX Extensions library, among other things, provides client-side classes that extend the DOM and provide you with tools that allow you to code in a browser agnostic manner (though there currently are still issues with Safari compatibility). These client-side classes also allow you to add behaviors to your HTML elements. To switch to an imperative model, you will need to replace the XML markup with two JavaScript functions. The first one is a generic script to add floating behavior to an HTML element. It leverages the AJAX Extensions client-side classes to accomplish this: <script type="text/javascript">
function addFloatingBehavior(ctrl, ctrlHandle){
$create(Sys.Preview.UI.FloatingBehavior,
{'handle': ctrlHandle},null, null, ctrl);
}
</script>
The function takes two parameter values: the HTML element that you want to make draggable, and the HTML element that is the drag handle for the dragging behavior. The new Now, you need to call the " There are actually a few workarounds for this, but the easiest one is to use a custom AJAX Extensions event called " <script type="text/javascript">
function pageLoad(){
addFloatingBehavior(document.getElementById('draggableDiv'),
document.getElementById('handleBar'));
}
</script>
which, in turn, can be written this way, using an AJAX Extensions script shorthand that replaces " <script type="text/javascript">
function pageLoad(){
addFloatingBehavior($get('draggableDiv'),$get('handleBar'));
}
</script>
And once again, you have a draggable III. Dynamic Drag DropSince the declarative model is much cleaner than the imperative model, why would you ever want to write your own JavaScript to handle AJAX Extensions behaviors? You might want to roll your own JavaScript if you want to add behaviors dynamically. One limitation of the declarative model is that you can only work with objects that are initially on the page. If you start adding objects to the page dynamically, you cannot add the floating behavior to them using the declarative model. With the imperative model, on the other hand, you can. Building on the previous example, you will replace the " function createDraggableDiv() {
var panel= document.createElement("div");
panel.style.height="100px";
panel.style.width="100px";
panel.style.backgroundColor="Blue";
var panelHandle = document.createElement("div");
panelHandle.style.height="20px";
panelHandle.style.width="auto";
panelHandle.style.backgroundColor="Green";
panel.appendChild(panelHandle);
var target = $get('containerDiv').appendChild(panel);
addFloatingBehavior(panel, panelHandle);
}
You will then just need to add a button to the page that calls the " <input type="button" value="Add Floating Div" onclick="createDraggableDiv();" />
<div id="containerDiv" style="background-color:Purple;height:800px;width:600px;"/>
This will allow you to add as many draggable elements to your page as you like, thus demonstrating the power and flexibility available to you once you understand the relationship between using AJAX Extensions declaratively and using it programmatically. As a point of reference, here is the complete code for the dynamic drag and drop example: <%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Imperative Drag and Drop II</title>
<script type="text/javascript">
function createDraggableDiv() {
var panel = document.createElement("div");
panel.style.height="100px";
panel.style.width="100px";
panel.style.backgroundColor="Blue";
var panelHandle = document.createElement("div");
panelHandle.style.height="20px";
panelHandle.style.width="auto";
panelHandle.style.backgroundColor="Green";
panel.appendChild(panelHandle);
var target = $get('containerDiv').appendChild(panel);
addFloatingBehavior(panel, panelHandle);
}
function addFloatingBehavior(ctrl, ctrlHandle){
$create(Sys.Preview.UI.FloatingBehavior,
{'handle':
ctrlHandle}, null,
null, ctrl);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js"
/>
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js"
/>
</Scripts>
</asp:ScriptManager>
<h2>Imperative Drag and Drop Code with javascript:
demonstrate dynamic loading of behaviors</h2>
<input type="button" value="Add Floating Div"
onclick="createDraggableDiv();"
/>
<div id="containerDiv"
style="background-color:Purple;height:800px;width:600px;"/>
</form>
</body>
</html>
IV. Declarative DropzonesBeing able to drag HTML elements around a page and have them stay where you leave them is visually interesting. To make this behavior truly useful, though, an event should be thrown when the drop occurs. Furthermore, the event that is thrown should depend on where the drop occurs. In other words, there needs to be behavior that can be added to a given HTML element that will turn it into a "dropzone" or a "drop target", the same way that the floating behavior can be added to an HTML In the following examples, I will show how Atlas supports the concept of dropzones. In its current state, Atlas does not support an out-of-the-box behavior for creating dropzone elements in quite the same way it does for floating elements. It does, however, implement behaviors for a The main disadvantage of the dragdropzone behavior is that it only works with items that have been decorated with the Atlas adds several OOP extensions to JavaScript in order to make it more powerful, extensions such as namespaces, abstract classes, and interfaces. You will take advantage of these in coding up your own dropzone behavior. If you peer behind the curtain and look at the source code in the PreviewDragDrop.js file, (contained in the directory C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\ScriptLibrary\Debug), you will find several interfaces defined there, including one for Sys.Preview.UI.IDragSource = function Sys$Preview$UI$IDragSource() {
}
Sys.Preview.UI.IDragSource.prototype = {
get_dragDataType: Sys$Preview$UI$IDragSource$get_dragDataType,
getDragData: Sys$Preview$UI$IDragSource$getDragData,
get_dragMode: Sys$Preview$UI$IDragSource$get_dragMode,
onDragStart: Sys$Preview$UI$IDragSource$onDragStart,
onDrag: Sys$Preview$UI$IDragSource$onDrag,
onDragEnd: Sys$Preview$UI$IDragSource$onDragEnd
}
Sys.Preview.UI.IDragSource.registerInterface('Sys.Preview.UI.IDragSource');Sys.Preview.UI.IDropTarget = function Sys$Preview$UI$IDropTarget() {}
Sys.Preview.UI.IDropTarget.prototype = {
get_dropTargetElement: Sys$Preview$UI$IDropTarget$get_dropTargetElement,
canDrop: Sys$Preview$UI$IDropTarget$canDrop,
drop: Sys$Preview$UI$IDropTarget$drop,
onDragEnterTarget: Sys$Preview$UI$IDropTarget$onDragEnterTarget,
onDragLeaveTarget: Sys$Preview$UI$IDropTarget$onDragLeaveTarget,
onDragInTarget: Sys$Preview$UI$IDropTarget$onDragInTarget
}
Sys.Preview.UI.IDropTarget.registerInterface('Sys.Preview.UI.IDropTarget');
Why do you need to implement these interfaces instead of simply writing out brand new classes to support drag, drop, and dropzones? The secret is that, behind the scenes, a third class, called the Type.registerNamespace('Custom.UI');
Custom.UI.DropZoneBehavior = function(value) {
Custom.UI.DropZoneBehavior.initializeBase(this, [value]);
initialize: function() {
Custom.UI.DropZoneBehavior.callBaseMethod(this, 'initialize');
// Register ourselves as a drop target.
Sys.Preview.UI.DragDropManager.registerDropTarget(this);
},
dispose: function() {
Custom.UI.DropZoneBehavior.callBaseMethod(this, 'dispose');
},
getDescriptor: function() {
var td = Custom.UI.DropZoneBehavior.callBaseMethod(this,
'getDescriptor');
return td;
},
// IDropTarget members.
get_dropTargetElement: function() {
return this.get_element();
},
drop: function(dragMode, type, data) {
alert('dropped');
},
canDrop: function(dragMode, dataType) {
return true;
},
onDragEnterTarget: function(dragMode, type, data) {
},
onDragLeaveTarget: function(dragMode, type, data) {
},
onDragInTarget: function(dragMode, type, data) {
}
}
Custom.UI.DropZoneBehavior.registerClass('Custom.UI.DropZoneBehavior',
Sys.UI.Behavior, Sys.Preview.UI.IDragSource,
Sys.Preview.UI.IDropTarget, Sys.IDisposable);
if(typeof(Sys) != "undefined") {Sys.Application.notifyScriptLoaded();}
I need to explain this class a bit backwards. The first thing worth noticing is the second to last line that begins " Next, you implement the You should now write up a page to show off your new custom dropzone behavior. You can build on the previous samples to accomplish this. In the Script Manager, besides registering the PreviewDragDrop script, you will also want to register your new DropZoneBehavior script: <asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript" />
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop" />
<asp:ScriptReference
Path="scriptLibrary/DropZoneBehavior.js" />
</Scripts>
</asp:ScriptManager>
Next, you will want to add a new <div style="background-color:Red;height:200px;width:200px;">
<div id="draggableDiv"
style="height:100px;width:100px;background-color:Blue;">
<div id="handleBar"
style="height:20px;width:auto;background-color:Green;">
</div>
</div>
</div>
<div id="dropZone" style="background-color:cornflowerblue;
height:200px;width:200px;">
Drop Zone
</div>
Finally, you need to add a declarative markup element to add your custom DropZone behavior to the <script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005"
xmlns:JavaScript="Custom.UI">
<components>
<control id="dropZone">
<behaviors>
<JavaScript:DropZoneBehavior/>
</behaviors>
</control>
<control id="draggableDiv">
<behaviors>
<floatingBehavior handle="handleBar"/>
</behaviors>
</control>
</components>
</page>
</script>
The code you have just written should basically add a drop zone to the original declarative drag and drop example. When you drop your drag element on the drop zone, an alert message should now appear. You can expand on this code to make the drop method of your custom dropzone behavior do much more interesting things, such as firing off other JavaScript events in the current page or even calling a web service, using ASP.NET AJAX, that will in turn process server-side code for you. V. Imperative DropzonesTo create dropzones using JavaScript instead of declarative script, just add the following JavaScript function to initialize your dropzone element with the custom dropzone behavior: function addDropZoneBehavior(ctrl){
$create(Custom.UI.DropZoneBehavior, {}, null, null, ctrl);
}
To finish hooking everything up, call this <%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Imperative Drop Targets</title>
<script type="text/javascript">
function addFloatingBehavior(ctrl, ctrlHandle){
$create(Sys.Preview.UI.FloatingBehavior,
{'handle': ctrlHandle}, null, null,
ctrl);
}
function addDropZoneBehavior(ctrl){
$create(Custom.UI.DropZoneBehavior,
{}, null, null, ctrl);
}
function pageLoad(){
addDropZoneBehavior($get('dropZone'));
addFloatingBehavior($get('draggableDiv'),$get('handleBar'));
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript"/>
<asp:ScriptReference
Name="Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop"/>
<asp:ScriptReference
Path="scriptLibrary/DropZoneBehavior.js"/>
</Scripts>
</asp:ScriptManager>
<h2>Imperative Drop Targets with javacript</h2>
<div style="background-color:Red;height:200px;width:200px;">
<div id="draggableDiv"
style="height:100px;width:100px;background-color:Blue;">
<div id="handleBar"
sstyle="height:20px;width:auto;background-color:Green;">
</div>
</div>
</div>
<div id="dropZone" style="background-color:cornflowerblue;
height:200px;width:200px;">Drop Zone</div>
</form>
</body>
</html>
Besides the dropzone behavior, you may want to also write your own floating behavior. For instance, by default, elements decorated with the floating behavior simply stay where you drop them. You may want to extend this so that your floating This tutorial is for the most part a straight translation of the original Atlas tutorial that I wrote against the April CTP. Even though many of the concepts behind Atlas are still retained in AJAX Extensions, some have changed by a turning of the screw so that what was once fitting and accurate in the original tutorial is no longer quite so. For instance, whereas in the original Atlas tutorial I could talk about XML scripting and the rest of the ASP.NET AJAX functionality as one technology, they are now currently two varying technologies with different levels of support and interest for Microsoft. There are more subtle differences that, I think, make the current version of the tutorial somewhat dated, as if I am saying everything with a slight accent; in other words, while I stand by the accuracy of this tutorial, I think it has lost some of its original elegance in the translation. I believe the tutorial will still be useful for those trying to get started with Microsoft's AJAX implementation, though its chief utility, at this point, will probably be for people who were used to the Atlas way of doing things and need a point of reference to see how the semantics of the technology has changed. I hope the samples will help you over some of your growing pains, as writing it has helped me with mine.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||