Monday, February 20, 2006

Creating a custom server control for ATLAS

When working with drag and drop lists in Atlas one task that you'll find yourself doing over and over again is adding the draggableListItem behavior to the controls that you wish to make "draggable" in your page's XML-Script. In many cases you may want to dynamically generate these controls with server side code based on results from a database query, for instance. For this reason, I thought it would make sense to build a custom web control to achieve this goal.

Rather than starting from scratch, I chose to start my control inheriting from the Panel control. This allows you to add any arbitrary content to the "draggable" item control, as it is translated to a span tag in HTML. In order to make the control "ATLAS-enabled" you need to implement the IScriptControl interface. The control's class declaration should be something similar to this:

public class DraggablePanel : System.Web.UI.WebControls.Panel, IScriptControl

Next you need to make sure to get a reference of the page's ScriptManager and register the control, and optionally you may want to add a reference to the AtlasUIDragDrop library to save you from doing that in the main page:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (!DesignMode)
{
ScriptManager scriptManager = ScriptManager.GetCurrent(Page);
if (scriptManager != null)
{
scriptManager.RegisterControl(this);
scriptManager.RegisterScriptReference(
FrameworkScript.AtlasUIDragDrop);
}
}
}


Next, the only method from the IScriptControl interface that must be implemented is the RenderScript method. The goal of the custom control is to output the following XML-Script:
<control id="webPart1">
<behaviors>
<draggablelistitem handle="webPart1Title">
</behaviors>
</control>

The RenderScript implementation will output the XML-Script above, using the control's id and the panel control's id as the handle:

public void RenderScript(ScriptTextWriter writer)
{
//Outputs control tag
GenericScriptComponent gsc = new GenericScriptComponent(
new ScriptTypeDescriptor("control",
ScriptNamespace.Default));
//Outputs behaviors tag
gsc.ID = this.ClientID;
GenericScriptComponent draggableBehavior =
new GenericScriptComponent(
new ScriptTypeDescriptor("draggableListItem",
ScriptNamespace.Default));
draggableBehavior.AddValueProperty("handle", this.ClientID);
gsc.AddCollectionItem("behaviors", draggableBehavior);
((IScriptObject)gsc).RenderScript(writer);
}

12 comments:

Matt said...

Hi, this is exactly what I've been looking for, but do have any sample pages that I could at? Thanks.

Jorge Balderas said...

The code to add controls dynamically in your page is fairly simple, here's a sample:

for (int i=0; i<5; i++) {
 DraggablePanel panel = new DraggablePanel();
 panel.Controls.Add(new Label(i.ToString()));
  //list is a runat server div element
 this.list.Controls.Add(panel);
}

matt said...

I'm a little new to Atlas, but I'm having problems implementing iScriptControl. Is there a DLL I need to reference? I get a "Namespace could not be found" for the following line. Thanks.

public class DraggablePanel : System.Web.UI.WebControls.Panel, iScriptControl

Jorge Balderas said...

Yes you need to add the Microsoft.Web.Atlas.dll assembly, you can get it from here:

Colin said...

So once I have the dragablelistitem how do I programmatically create and add a dragdroplist?

Jorge Balderas said...

Colin,
To programatically add DraggablePanel controls, you need to:
1. Add a HTML control (e.g. a div or td element) with the runat server attribute:
>td id="queueList" runat="server"<

2. Then you also need in your XML-Script to add the DragDropList behavior to this HTML element (the control id needs to match the HTML element id):

<control id="queueList">
<behaviors>
<dragDropList dataType="HTML" acceptedDataTypes="'HTML'" dragMode="Move">
<dropCueTemplate />

3. Finally you can programmatically add DraggablePanel instances to the Controls collection of your HTML element:

this.queueList.Controls.Add(draggablePanel);

Colin said...

Nevermind, I just did what you did for the panel - but derived from tablecell instead. Good post!

Colin said...

Thanks for your response. I actually wanted to create the drop list at runtime so I did this:

public class DroppableCell : System.Web.UI.WebControls.TableCell, IScriptControl
{
...you get the picture
}

So now I can do "new DroppableCell().Controls.Add(new DraggablePanel())"

But your post put me in the right direction, thanks!

Anonymous said...

Hey, Jorge Balderas
Thank you very much for this knowledge share. It helped me a lot with implementing some of my requirements. Keep sharing your remarkable thoughts.

Lior

San Kinsey said...

Hi, I followed your example code and managed to get things to work, the only proble is, it only works in IE.
I've got a post about it here

Any thoughts?

Haresh said...

Finally!!! after so much of googling I found your blog! excellent work Jorge.

But as kinsey said it doesn't work in Firefox. Could you please let us know if you have any solution for this problem?

Thanks.

Haresh said...

Ignore my previous comment Jorge. It works on Firefox as well! that was just a javascript error in my code ...Okay, I need sleep :)