Monday, July 07, 2008

blackstone

The problem with conjuring tricks is that they lose practically all their glamour once you find out how they are done.  It's very cool to see David Blaine walk down the street, do a few passes over his hand, and resurrect a fly which proceeds to flee.  It's rather disappointing to do a google search and discover that in order to prepare for this trick, the first requirement is that you freeze a fly.

My trick is to make an autocomplete extender from the Ajax Control Toolkit call a WCF service instead of an asmx service.  For this recipe, I assume that you are already familiar with the autocomplete extender, and that you are using Visual Studio 2008.  I warn you in advance -- my trick disappoints.  It is so trivially easy that, once the technique spreads, it is very unlikely to impress your colleagues at work, much less get you a date with a supermodel.

posted by J Ashley on Monday, July 07, 2008 2:23:31 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Thursday, July 03, 2008

ajax

Ajax, the fleet son of Oileus, commanded the Locrians. He was not so great, nor nearly so great, as Ajax the son of Telamon. He was a little man, and his breastplate was made of linen, but in use of the spear he excelled all the Hellenes and the Achaeans. --The Iliad

Ajax son of Oileus is traditionally called Ajax the Lesser, while Ajax Telamon's son is Ajax the Greater.  The Trojan War  is often portrayed as a battle between the national heroes of two great armies, Hector on one side, and Achilles on the other.  What makes the arraying of the sides peculiar is that, in fact, the Achaeans have two heroes that can defeat the war chief of the Trojans.  Both Achilles and Ajax the Greater are superior warriors to Hector.  This feature was actually a giveaway to many classicists back in 1959 that the newly released western Warlock was based on The Iliad.

Two years ago Microsoft began a campaign to carve out a niche in the Ajax world...

posted by J Ashley on Thursday, July 03, 2008 7:34:33 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Friday, June 13, 2008

multi-tabs

 

download source code

ASP.NET has been missing a good, free tab control for a long time.  With the ACT Tab Container, we were finally given one.  It typically runs in client-side only mode, but can interact with server-code if we set its AutoPostback property to true.

Compared to what we had before, it is a huge improvement.  The peculiar thing about it, however, is that it isn't actually an Ajax control.  It doesn't use asynchronous postbacks or web service calls to talk to the server -- instead you just have these two mode: run it using client script only, or run it using server-side events and code-behind only.

So a few months ago I rectified this for a project, and only found out afterwards that Matt Berseth had already outlined the technique on his blog.  You basically run the tab container in client-side mode, and add update panels to the tab panels that you want to be ajaxy.  You then hook up the client-side ActivePageChanged event in such a way that it spoofs the Update Panel contained in the tab, causing an asynchronous (or partial) postback.

Matt also gave this technique a cool name.  He called it 'lazy loading the tab panel'.  Like lazy loading in OOP, using this technique the update panels inside each tab panel only do something when its tab is selected.  Information is loaded only when its needed, and not before.

I must admit that I hold some resentment against Matt for coming up with this first, and for coming up with the cool moniker for it.  On the other hand, the solution I came up with encapsulates all of the javascript needed for this into a nice simple extender control that you can drop on your page, which his does not, and I'm rather proud of this.

The VS 2008 project for this extender is linked at the top of this post.  To use it, you need to compile the project and add the compiled assembly to your project, or else just add the project to your solution and add a project reference.

1. Drop the TabContainerExtender control into your page.

2. Set the Extender's TargetControlID property to your TabContainer's ID.

3. In the RegisterUpdatePanels element of the Extender, map your tabs to your update panels.  This mapping tells the extender which Update Panels to activate when each tab is selected.

Your markup will look something like this:

    <cc2:TabContainerExtender ID="TabContainerExtender1" 
    runat="server" 
    TargetControlID="TabContainer1" OnActiveTabChanged="ActiveTabChanged">
    <RegisterUpdatePanels>
    <cc2:UpdatePanelInfo TabIndex="0" UpdatePanelID="UpdatePanel1" />
    <cc2:UpdatePanelInfo TabIndex="1" UpdatePanelID="UpdatePanel2" />
    <cc2:UpdatePanelInfo TabIndex="2" UpdatePanelID="UpdatePanel3" />
    </RegisterUpdatePanels>
    </cc2:TabContainerExtender> 

4. If you want to add some code-behind to your active tab changed event, add set the OnActiveTabChanged property of the Extender to the name of your handler.  The thrown event will pass the correct Index number for the active Tab, as well as the ID of the mapped Update Panel.  The handler's signature looks like this:

        protected void ActiveTabChanged(int index, string panelID)

        {

            ...

        }

I highly encourage you to read Matt Berseth's blog entry (which I have to admit is pretty good) to get a clear idea of the techniques being applied in this ajax extender.  If you just need a quick solution, however, feel free to download this code from the link at the top and use it any way you like with no strings attached.  There is a sample project attached to the solution that will demonstrate how to use the Tab Container Extender, in case you run into any problems with lazy loading your panels.

For reference, here is the code for the sample implementation, which loads controls on the fly based on the tab selected:

    <cc1:TabContainer ID="TabContainer1" runat="server">
    <cc1:TabPanel ID="TabPanel1" runat="server" HeaderText="Tab Panel 1">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
        Content 1 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
        <cc1:TabPanel ID="TabPanel2" runat="server" HeaderText="Tab Panel 2">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel2" runat="server">
        <ContentTemplate>
        Content 2 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
        <cc1:TabPanel ID="TabPanel3" runat="server" HeaderText="Tab Panel 3">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel3" runat="server">
        <ContentTemplate>
        Content 3 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
    </cc1:TabContainer>
    <cc2:TabContainerExtender ID="TabContainerExtender1" 
    runat="server" 
    TargetControlID="TabContainer1" OnActiveTabChanged="ActiveTabChanged">
    <RegisterUpdatePanels>
    <cc2:UpdatePanelInfo TabIndex="0" UpdatePanelID="UpdatePanel1" />
    <cc2:UpdatePanelInfo TabIndex="1" UpdatePanelID="UpdatePanel2" />
    <cc2:UpdatePanelInfo TabIndex="2" UpdatePanelID="UpdatePanel3" />
    </RegisterUpdatePanels>
    </cc2:TabContainerExtender> 
posted by J Ashley on Friday, June 13, 2008 1:35:50 PM (Eastern Standard Time, UTC-05:00)  #    Comments [2]
 Sunday, January 06, 2008

Following the recent release of Visual Studio 2008, I scribed a new tutorial on ASP.NET AJAX Custom Controls using the new IDE.  I originally estimated two weeks for the project, but in order to put in everything I thought needed to be said about writing AJAX-enabled .NET controls, the effort took over six weeks.  Should you have any inclination to see it, you can find it here at www.codeproject.com.

The tutorial is built around the session timeout monitor I originally described at the Imaginative Universal: http://www.imaginativeuniversal.com/SessionExpiredMonitorWithASPNETAJAX.aspx.  Since the code for the tutorial is intended primarily to be instructive, I still plan to write one more revision of the session timeout control, in order to streamline the functionality and try to incorporate the modal popup behavior from the AJAX Control Toolkit, which I will publish in the pages of this blog.

posted by J Ashley on Sunday, January 06, 2008 3:02:38 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Friday, October 19, 2007

timeout

code download

Sessions are a way of preserving information on a web site between page hits, allowing the programmer to emulate a stateful application when, in fact, web pages are not really stateful.  They are also one of the banes of web development, since sessions eventually timeout when there is no interaction between the user and the web app for a prolonged period of time.  In ASP.NET, this period has a default of 20 minutes, which is really hardly enough time to pick up a donut, refill one's coffee, and chat with fellow workers before returning to one's computer.  What this often means is that the user, upon returning to their computer and continuing work after a 20 minute break will find that all of the data entry they have been doing has been lost.  Worse, strange errors will begin to appear in his web browser if the loss of a session is not handled gracefully. 

The most common workaround is to increase the session grace period, called the session timeout.  This is set in your web.config file, and typically looks like this (the timeout period is measured in minutes):

  <system.web>
    <sessionState
      mode="InProc"
      cookieless="false"
      timeout="20"
     />
posted by J Ashley on Friday, October 19, 2007 4:56:45 AM (Eastern Standard Time, UTC-05:00)  #    Comments [2]
 Thursday, October 11, 2007

I have updated the Drag and Drop tutorial code samples for the July CTP.  The samples can be downloaded here: link.

The tutorial pages can be found here:

  1. Introduction
  2. Declarative Drag and Drop
  3. Imperative Drag and Drop
  4. Dynamically Generated Drag Items
  5. Working with Dropzones

The July CTP can be downloaded here: link.

posted by J Ashley on Thursday, October 11, 2007 3:58:23 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]
 Tuesday, September 04, 2007

drinking_horn

There are various legends about drinking with the Immortals.  They typically involve a wanderer lost in the wilderness who is offered shelter by strange people.  He is brought close to the fire and given beer, or wine, or mead, depending on the provenance of the folktale.  As his clothes dry out, he is regaled by tales of ancient times and slowly comes to realize that his companions are not typical folk, but rather denizens from behind the veil.  He has fallen, through no merit of his own, into the midst of an enchanted world, and his deepest fear is not of the danger that is all around him, but rather that once the enchantment is disspelled, he will never be able to recover it again.

It occurred to me recently that I had such an experience about a year ago.  I was sent by my company to the Microsoft campus in Redmond to spend several days with the ASP.NET Team and other luminaries of the .NET world.

The names will mean nothing to most readers, but I had the opportunity to meet Bertrand LeRoy, Scott Guthrie, Eilon Lipton, and others to discuss the (then new) ASP.NET Ajax.  I had been painfully working through the technology for several months, and so found myself able to almost hold a conversation with these designers and developers.

On the final night of the event all the seminar attendees were taken to a local wine bar and had dinner.  As is my wont, I drank as much free wine as was poured into my glass, and began spinning computer yarns that became more and more disassociated from reality as the night wore on.  I'm sure I became rather boorish at some point, but the Microsoft developers listened politely, and in my own mind, of course, I was making brilliant conversation.

Even to those who know something of the people I was talking to, this might seem like no big deal.  I went drinking with colleagues in the same industry I am in -- so what.  But for me, it was as if I were suddenly introduced to the people who make the rain that nourishes my fields and the sunlight that warms my days.  Microsoft software simply appears as if by magic out of Redmond, and like millions of others, day in and day out, I dutifully learn and use the new technologies that come out of the software giant.  To find out that there are actually people who design the various tools I use, and build them, and debug them -- this is a bit difficult to conceive.

In A Room of One's Own, Virginia Woolf reflects on Charles Lamb's encounter with a dog-eared manuscript of one of Milton's poems, filled with lines scratched out and re-written, words selected and words discarded:

"Lamb then came to Oxbridge perhaps a hundred years ago. Certainly he wrote an essay-the name escapes me-about the manuscript of one of Milton's poems which he saw here. It was LYCIDAS perhaps, and Lamb wrote how it shocked him to think it possible that any word in LYCIDAS could have been different from what it is. To think of Milton changing the words in that poem seemed to him a sort of sacrilege."

My own discovery that the things of this world which I consider most solid and most real -- because they are so essential to my daily life -- could have been otherwise than they are, was a similar moment of shock, tinged with fear. 

In a moment of anxiety during this sweet symposium, I leaned over to the person immediately to my right and confided in him my strange reflections.  He laughed gently, and dismissed my drunken observations about the contingent nature of reality.  I later found out he was the twenty-three year old developer of the ASP.NET login control, used daily in web applications around the world, when he inquired of me whether I had ever used his control, and what I thought of it.

posted by J Ashley on Tuesday, September 04, 2007 11:50:59 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1]
 Tuesday, January 23, 2007

It was over a year ago that I started working with a product called Microsoft Atlas.  I wanted to use it to build a rich web client for managing licensed commercial music for a cable television studio, based on the expectation that the client must work on multiple platforms (hence a web application) and at the same time provide rich functionality such as our sponsors were used to in their desktop applications (hence Ajax).  The whole time I was building it, I had the expectation that the final release was right around the corner.  In December of 2005, Atlas was rumored to have a release date sometime in the March or April range.  A year, a name change, and a few scope changes later, it has finally arrived.

The product is an example of Microsoft coming late to the party.  Based on a key bit of technology originally developed by Microsoft engineers over seven years ago, the XMLHttpRequest API, alternate vendors like Yahoo, Google and others helped to develop a style of programming called Ajax that allowed web clients to talk to a webserver without a page refresh.  Ajax in turn was adopted by advocates of the term Web 2.0 as one of the hallmarks of the phenomena they wished to tout in an attempt to revitalize interest in the web as a business platform following the disaster that we now all know as The IT Bubble of the 90's.

Why Microsoft took so long to get around to it is an open question.  Very likely, they were busy getting on the web services band wagon as a way to promote Smart Clients as their technology of choice for integrating the desktop with the web.  While very cool in its own right, it hasn't really achieved the same mindshare that Ajax has among web developers, and so -- better late than never -- we now have ASP.NET Ajax to kick around, and it can be downloaded here.

In the meantime, special recognition should be given, I think, to Brent Ashley, who in 2000 came out with something he called JavaScript Remote Scripting, which used javascript to generate dynamic iFrames in order to provide the same functionality that the XMLHttpRequest API does.  In an alternate universe, JSRS could have been the inspiration for Web 2.0.  Brent Ashley still supports his scripts here, a placeholder for his mark on the history of technology.

posted by J Ashley on Tuesday, January 23, 2007 3:46:45 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Friday, November 17, 2006
There are a few good guides already on the internet that provide an overview of what is required to convert your Atlas CTP projects to Ajax Extensions. This guide is intended to consolidate some of the advice already provided, as well as offer a few pointers alluded to by others but not explained. In other words, this is the guide I wish I had before I began my own conversion project.
posted by J Ashley on Friday, November 17, 2006 5:28:37 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
To create dropzones using JavaScript instead of declarative script, just add the following JavaScript function to initialize your dropzone element with the custom dropzone behavior...
posted by J Ashley on Friday, November 17, 2006 12:36:11 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
Being 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 div tag to turn it into a drag and drop element. In the following examples, I will show how Atlas supports the concept of dropzones.
posted by J Ashley on Friday, November 17, 2006 12:14:45 PM (Eastern Standard Time, UTC-05:00)  #    Comments [2]
Since 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.
posted by J Ashley on Friday, November 17, 2006 11:56:44 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
To 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.
posted by J Ashley on Friday, November 17, 2006 11:48:53 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
The first task is to use XML markup to add drag-drop behavior to a div tag. By drag and drop, I just mean the ability to drag an object and the have it stay wherever you place it. The more complicated behavior of making an object actually do something when it is dropped on a specified drop target will be addressed later in this tutorial.
posted by J Ashley on Friday, November 17, 2006 11:39:09 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
The hardworking Atlas/Ajax team has greatly improved the architecture of the Ajax Extensions framework with the Beta 2, making it much more rational and easy to use for future adopters. Sadly, for us early adopters, this also meant a large number of breaking changes and a bit of a struggle trying to figure out the new paradigms for programming ASP.Net. At this point in time, the documentation hasn't yet caught up with the innovation, and so the best place to look for reliable information about how to use ASP.Net is to go the professional blogs of the various Microsoft developers: Bertrand LeRoy, Eilon Lipton, Scott Guthrie. The blog of Miljan Braticevic of Component Art was also extremely helpful.
posted by J Ashley on Friday, November 17, 2006 11:21:56 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Wednesday, October 25, 2006

 As mentioned in a previous post, programmers typically explain one technology by referencing another more familiar technology.  What sometimes happens, however, is that the technology that was thought to be more familiar, and consequently believed to have explanatory power, in fact was simply originally explained by referencing some third vaguely understood technology; but time made the simile comfortable and vanity made it acceptable.  We only become aware of the semantic web we programmers weave when we are finally forced to use one of the referenced technologies and discover, once again, what a strange and incomprehensible thing programming is.  The experience is a bit like the shock felt by the woman who brought home a stray dog from Paris only to discover that it was really a large tailless rat.

To find out what one of the trendier new technologies is really like, I recently consulted Google.  A google search on "Ajax is like..." turns up the following results:

"Comparing Java and AJAX is like comparing apples and blue."

"[U]sing Ajax is like consuming alcohol in public."

"[A]jax is like instant messaging...."

"Customers asking for AJAX is like a prospective homeowner walking over to the contractors hired to do the building and handing them a saw."

"AJAX is like Flash or HTML."

"AJAX is like a javascript."

"AJAX is like Javascript on steroids."

"AJAX is like web services."

"[A]jax is like everything else on line, it will be abused by various low lifes."

"Ajax is like to partial update in Intraweb I am wrong?"

"Ajax is like 'roller skates for the web.'"

"Ajax is like shell, Perl, Ruby. Ajax is like UNIX."

"AJAX is like a Hooker turn School Teacher, it has a dirty secret and unless you get it alone and play with it, you won't pickup on it's secrets until it's too late."

"Ajax is, like stated in the essay, a new way to think about user interfaces on the web...."

"AJAX is like wearing 70's djeans with an Hugo Boss Shoes...."

"AJAX is like Dinosaur cloning in Jurassic park."

"AJAX is like folding a web page origami-style into a Lego brick...."

"AJAX is like a house of cards, and when a browser vendor screws up on a revision it'll all come tumbling down."

"AJAX is like putting a tiny bandage on a gaping wound the size of a grapefruit."

"Ajax is like DHTML was 4 years ago, like javascript was 6 years ago, like applets were 8 years ago."

"AJAX is like the killer buzzword."

posted by J Ashley on Wednesday, October 25, 2006 11:32:44 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Wednesday, October 18, 2006

 

To 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){
    var dropZone = new Sys.UI.Control(ctrl);
    var dropZoneBehavior = new Custom.UI.DropZoneBehavior();
    dropZone.get_behaviors().add(dropZoneBehavior);
    dropZoneBehavior.initialize();
}

To finish hooking everything up, call this addDropZoneBehavior function from the Atlas pageLoad() method, as you did in earlier examples for the addFloatingBehavior function. This will attach the proper behaviors to their respective HTML elements and replicate the drag and dropzone functionality you created above using declarative markup. If you want to make this work dynamically, just add the createDraggableDiv() function you already wrote for the previous dynamic example. As a point of reference, here is the complete code for creating programmatic dropzones:

<%@ 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){
        var floatingBehavior = new Sys.UI.FloatingBehavior();
        floatingBehavior.set_handle(ctrlHandle);
        var dragItem = new Sys.UI.Control(ctrl);
        dragItem.get_behaviors().add(floatingBehavior);
        floatingBehavior.initialize();
    }
    function addDropZoneBehavior(ctrl){
        var dropZone = new Sys.UI.Control(ctrl);
        var dropZoneBehavior = new Custom.UI.DropZoneBehavior();
        dropZone.get_behaviors().add(dropZoneBehavior);
        dropZoneBehavior.initialize();
    }
 
    function pageLoad(){
        addDropZoneBehavior($('dropZone'));
        addFloatingBehavior($('draggableDiv'),$('handleBar')); 
    }
</script>
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
<atlas:ScriptReference Path="scriptLibrary/DropZoneBehavior.js" />
</Scripts>
</atlas: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" 
             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>
</form>
</body>
</html>
 

Conclusion

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 div will snap back to its original location when you drop it outside of a drop zone. Additionally, you may want to change the way the dragged element looks while you are dragging it, either by making it transparent, changing its color, or replacing the drag image altogether. All this can be accomplished by creating a behavior that implements the IDragSource interface in the same way you created a custom class that implements the IDropTarget interface.

This tutorial should provide you with a starting point for extending the basic drag drop functionality provided with Atlas, to create your own behaviors and provide your own functionality. The next step is to build on this to create controls. Using this tutorial as a starting point, you can go on to create Atlas extender controls that implement your behaviors using declarative markup, or even turn around and create server-side controls that automatically create HTML elements with Atlas behaviors, with the choice being, once again, one between creating server-side controls that are either declarative, and consequently static, or imperative, and consequently slightly more complex but also more flexible. This is a topic that is much too large for the current tutorial; however, I hope that in the near future, someone will try to do for server-side Atlas programming what this tutorial attempts to do for client-side Atlas scripting.

posted by J Ashley on Wednesday, October 18, 2006 7:57:50 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Tuesday, October 17, 2006

 

Being 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 div tag to turn it into a drag and drop element.

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 DragDropList element and a DraggableListItem element which, when used together, allow you to create lists that can be reordered by dragging and dropping. If you would like to explore this functionality some more, there are several good examples of using the DragDropList behavior on the web, for instance, Introduction to Drag And Drop with Atlas.

The main disadvantage of the dragdropzone behavior is that it only works with items that have been decorated with the DragDropList behavior. The functionality that this puts at your disposal is fairly specific. To get the sort of open-ended dropzone functionality I described above, that will also work with the predefined floating behavior, you will need to write your own dropzone behavior class in JavaScript. Fortunately, this is not all that hard.

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 AtlasUIDragDrop.js file, (you can do this with the Visual Studio debugger), you will find several interfaces defined there, including one for Sys.UI.DragSource and one for Sys.UI.DropTarget. In fact, both the FloatingBehavior class and the DraggableListItem class implement the Sys.UI.DragSource interface, while Sys.UI.DropTarget is implemented by the DragDropList class. The code for these two interfaces looks like this:

Sys.UI.IDragSource = function() {
    this.get_dataType = Function.abstractMethod;
    this.get_data = Function.abstractMethod;
    this.get_dragMode = Function.abstractMethod;
    this.onDragStart = Function.abstractMethod;
    this.onDrag = Function.abstractMethod;
    this.onDragEnd = Function.abstractMethod;
}
Sys.UI.IDragSource.registerInterface('Sys.UI.IDragSource');
Sys.UI.IDropTarget = function() {
    this.get_dropTargetElement = Function.abstractMethod;
    this.canDrop = Function.abstractMethod;
    this.drop = Function.abstractMethod;
    this.onDragEnterTarget = Function.abstractMethod;
    this.onDragLeaveTarget = Function.abstractMethod;
    this.onDragInTarget = Function.abstractMethod;
}
Sys.UI.IDropTarget.registerInterface('Sys.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 DragDropManager, is actually coordinating the interactions between the draggable elements and the dropzone elements, and it only knows how to work with classes that implement the IDragSource or the IDropTarget. The DragDropManager class registers which dropzones are legitimate targets for each draggable element, handles the MouseOver events to determine when a dropzone has a draggable element over it, and a hundred other things you do not want to do yourself. In fact, it does it so well that the dropzone behavior you are about to write is pretty minimal. First, create a new JavaScript file called DropZoneBehavior.js. I placed my JavaScript file under a subdirectory called scriptLibrary, but this is not necessary in order to make the dropzone behavior work. Next, copy the following code into your file:

Type.registerNamespace('Custom.UI');

Custom.UI.DropZoneBehavior = function() {

    Custom.UI.DropZoneBehavior.initializeBase(this);
    this.initialize = function() {
        Custom.UI.DropZoneBehavior.callBaseMethod(this, 'initialize');
        // Register ourselves as a drop target.
        Sys.UI.DragDropManager.registerDropTarget(this); 
    }
    this.dispose = function() {
        Custom.UI.DropZoneBehavior.callBaseMethod(this, 'dispose');
    }
    this.getDescriptor = function() {
        var td = Custom.UI.DropZoneBehavior.callBaseMethod(this, 'getDescriptor');
        return td;
    } 

    // IDropTarget members.
    this.get_dropTargetElement = function() {
        return this.control.element;
    }
    this.drop = function(dragMode, type, data) { 
        alert('dropped');
    }
    this.canDrop = function(dragMode, dataType) {
        return true;
    }
    this.onDragEnterTarget = function(dragMode, type, data) {
    }
    this.onDragLeaveTarget = function(dragMode, type, data) {
    }
    this.onDragInTarget = function(dragMode, type, data) {
    }
}
Custom.UI.DropZoneBehavior.registerClass('Custom.UI.DropZoneBehavior', 
       Sys.UI.Behavior, Sys.UI.IDragSource, 
       Sys.UI.IDropTarget, Sys.IDisposable);
Sys.TypeDescriptor.addType('script', 'DropZoneBehavior', 
                           Custom.UI.DropZoneBehavior);

I need to explain this class a bit backwards. The first thing worth noticing is the second to last line that begins with "Custom.UI.DropZoneBehavior.registerClass". This is where the dropZoneBehaviorClass defined above gets registered with Atlas. The first parameter of the registerClass method takes the name of the class. The second parameter takes the base class. The remaining parameters take the interfaces that are implemented by the new class. The line following this makes your class available for declarative markup scripting. Now back to the top, the "Type.registerNamespace" method allows you to register your custom namespace. The next line declares our new class using an anonymous method syntax. This is a way of writing JavaScript that I am not particularly familiar with, but is very important for making JavaScript object oriented, and is essential for designing Atlas behaviors. Within the anonymous method, the class methods Initialize, Dispose, and getDescriptor are simply standard methods used for all behavior classes, and in this implementation, all you need to do is call the base method (that is, the method of the base class that you specify in the second to last line of this code sample.) The only thing special you do is to register the drop target with the Sys.UI.DragDropManager in the Initialize method. This is the act that makes much of the drag drop magic happen.

Next, you implement the IDropTarget methods. In this example, you are only implementing two methods, "this.canDrop" and "this.drop". For "canDrop", you are just going to return true. More interesting logic can be placed here to determine which floating div tags can actually be dropped on a given target, and even to determine what sorts of floating divs will do what when they are dropped; but in this case, you only want a bare-bones implementation of IDropTarget that will allow any floating div to be dropped on it. Your implementation of the "drop" method is similarly bare bones. When a floating element is dropped on one of your drop targets, an alert message will be thrown indicating that something has occurred. And that's about it. You now have a drop behavior that works with the floating behavior we used in the previous examples.

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 Atlas Script Manager, besides registering the AtlasUIDragDrop script, you will also want to register your new DropZoneBehavior script:

<atlas:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
        <atlas:ScriptReference Path="scriptLibrary/DropZoneBehavior.js" />
    </Scripts>
</atlas:ScriptManager>

Next, you will want to add a new div tag to the HTML body, that can be used as a drop target:

<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 div you plan to use as a dropzone element. The XML markup should look like this:

<script type="text/xml-script">
    <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
        <components>
            <control id="dropZone">
                <behaviors>
                    <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 dropzone to the original declarative drag and drop example. When you drop your drag element on the dropzone, an alert message should 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 webservice, using Atlas, that will in turn process server-side code for you.

posted by J Ashley on Tuesday, October 17, 2006 9:15:26 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Monday, October 16, 2006

 

Since the declarative model is much cleaner than the imperative model, why would you ever want to write your own JavaScript to handle Atlas 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 "pageLoad()" function with a function that creates floating divs on demand. The following JavaScript function will create a div tag with another div tag embedded to use as a handlebar, then insert the div tag into the current page, and finally add floating behavior to the div tag:

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 = $('containerDiv').appendChild(panel);
    addFloatingBehavior(panel, panelHandle);
}

You will then just need to add a button to the page that calls the "createDraggableDiv()" function. The new HTML body should look something like this:

<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 Atlas 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 = $('containerDiv').appendChild(panel);
        addFloatingBehavior(panel, panelHandle);
    }
    function addFloatingBehavior(ctrl, ctrlHandle){
        var floatingBehavior = new Sys.UI.FloatingBehavior();
        floatingBehavior.set_handle(ctrlHandle);
        var dragItem = new Sys.UI.Control(ctrl);
        dragItem.get_behaviors().add(floatingBehavior);
        floatingBehavior.initialize();
    }
</script>
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <atlas:ScriptReference ScriptName="AtlasUIDragDrop" />
    </Scripts>
</atlas: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>
posted by J Ashley on Monday, October 16, 2006 9:44:35 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Friday, October 13, 2006

Source Code: AtlasDragNDrop.zip (467.5 KB)

Preface

I'm not sure if this explanation belongs in the preface or in the introduction, or what the exact difference is between the two.  In any case, this purpose of this preface is to explain why this tutorial is here.  I wrote it originally for a different site, codeproject.com, to which I have since lost my password.  At the same time, the underlying Atlas framework, upon which this tutorial is based and for which it is written, has gone through several iterations, thus obligating me to update this tutorial to make sure it is still valid.  So I've placed it here, in an easily accessible location, where I can quickly edit the text of this tutorial for as long as I can remember the password.  Who knows, should I find myself short of material again, I may start posting my journal article on Vico, grad school essays, and so on...

Introduction

This tutorial is intended to help readers understand how certain aspects of Microsoft's new Atlas technology works. Atlas 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 Atlas abstractions is the new XML markup syntax developed to make coding with Atlas easier. 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 AtlasUIDragDrop library file to perform basic drag-drop operations as well as set up drop zones.

Background

As I write this, Atlas is still in beta, and continues to change. These examples apply to the April CTP of Atlas. Newer releases of Atlas may affect the accuracy of this tutorial. I will attempt to update the code as new versions of Atlas become available. Atlas only works with .NET 2.0.

posted by J Ashley on Friday, October 13, 2006 2:37:07 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]