Welcome to MSDN Blogs Sign in | Join | Help

Atlas Control Tooklit online talk now available

A few weeks ago I did an online (LiveMeeting) talk about the Toolkit.  It finally got pushed out onto the download servers, so you can watch it here as a streaming video (WMV).  Note the first few minutes the screen will be blank (you'll get audio).  Don't worry, it's perfectly normal.

I posted the slides & samples in a prior post.

 

posted by sburke | 0 Comments

The next step for the Toolkit: Community Contributions

Well sometimes you need a little nudge, and we got just that via Scott's blog post earlier this week, kind of unexpectedly. 

So, uh, yeah, as some of you may have noticed, our content and code is now live on CodePlex in the Atlas Toolkit Project.  The Team and I have been getting used to the ins-and-outs of CodePlex and figuring out what our developement process is going to look like using it.  We've moved most of our code off of our internal source control servers up to CodePlex and have been doing our changes there.  The last major piece has been cleaning up our test infrastructure and moving that up as well.  That's kept us pretty busy but it's almost ready.

If you're not familiar with CodePlex, you can read all about it on Korby's blog, but I like to call it "TFS-in-the-sky".  You create a project on the website, type in some credentials into your Visual Studio 2005 configuration and - poof! - you've got integrated source control and issue tracking.  It's pretty darn cool really. So far so good. CodePlex is still in beta and they're scaling up slowly so they're not taking external projects quite yet. 

I heard about CodePlex when I was just starting my team, and this was exactly what we needed to push the "transparency envelope" and getting our stuff up on CodePlex wasn't anything that some emails, bribes, and good-old-fashioned whining couldn't accomplish (Okay - I'm kidding, they were really excited about having us on board and have been a pleasure to work with). 

I'm currently evaluting some potential contributors.  Right now I'd like to keep the number of contributors fairly small (10-or-so) so I can see how the process scales and make sure it all works smoothly.  Based on that we'll grow the list of direct (people with checkin rights) and indirect (people that can submit code through others) contributors.

So that's where we're at - I'm super-mega-excited about this and the great things that are going to come of it.  The Toolkit project has been a heckuvalotta fun so far and I'm betting that's just getting started.  Feel free to ask questions if you've got 'em.

posted by sburke | 1 Comments

"Atlas" Control Toolkit Refresh Released

We finally managed to get this refresh done.  Check out the samples and release notes at http://atlas.asp.net/atlastoolkit.

Or just click here to get the bits.

Lots of bug fixes, 4 new controls.  Not too many breaking changes.  Enjoy!

posted by sburke | 15 Comments

Toolkit refresh teaser


We've been busily working on the Toolkit refresh.  I'm not making any promises but I think we can get it out by the middle of next week.  Here's a short off-the-top-of-my-head list of what to expect:

Incorporated feedback.  We've addressed as much of the feedback from the community as we could.  We didn't get everything fixed but we did a lot.  In general, most of the components are more flexible and robust.


Safari support.  This has turned out to be a ton of work.  It's one thing to make HTML work across browsers, making framework pieces do it is quite another.  There's a set of things that Safari just doesn't plain support or that the Atlas guys are still trying to figure out how to map onto Safari's feature set..  So in those cases we weren't able to resolve everything.  But for the issues that we could work around or fix, we did; Safari has been much more challenging than FireFox, for example, and debugging is tough because you can't do it locally.  We're still not perfect but it's much better.


Functionality improvements.  We've added the ability to address page methods instead of just web services, greatly improved the network profile of CascadingDropDown, simplified several common operations in the extender base by making them Attribute-driven, added image support to CollapsiblePanel, and generally added some polish to the Toolkit components.


New extenders.  Right now we're looking at doing out with a DropShadow extender, a RoundedCorners extender, a modal popup/overlay extender, and an extender that lets you have one of those elements that stays visible when you scroll and tracks your position (the hardest part here has been what to name it!).  They're all super cool and we think you'll find great uses for them.

Anyway, just wanted to give you a sense of what we're up to.  Your feedback (direcly and via the forum) has been invaluable.  After we get this release out, we'll start focusing on getting the contribution model up and running - it should be fun!

 

posted by sburke | 18 Comments

Slides & Samples from Atlas Toolkit Talk

I've done a couple online talks about the Toolkit.  Here's the slides & demo that I did as part of the talk.

 

posted by sburke | 3 Comments
Attachment(s): AtlasToolkitDemo.zip

Explaining the Toolkit's Extender classes

All of the controls in the preview release of the Toolkit are built upon a set of classes that really help streamline the process of writing control extenders.  These classes form a thin "glue" layer between the Tookit controls and the "Atlas" classes as they exist today.  I'm really happy with how this stuff turned out and we enabled a bunch of things that take some work when doing control extenders by hand.  It's certainly made our lives easier, made the process considerably less error prone, and we'll continue to make improvements.  In fact, we've already made several great improvements that you'll see in the next release.  I'll highlight those changes here in italics.

To get the most out of this entry, you should have written a control with the toolkit, or at least read this walkthrough.

The Extender Classes automate a couple of major things:

·                     The generation of XML script that hooks up your behavior to an element on the page

·                     The loading of your script file reference

·                     The management of any scripts that your behavior or control may be dependant on

·                     The mapping of properties and their valeus from the managed side to the client script

·                     Help in developing and debugging your script

·                     A mechanism to move state back-and-forth between your extender and the behaviors in the browser

The main class is called Microsoft.AtlasControlExtender.ExtenderControlBase (we'll call it ECB here).  ECB is a generic, abstract class, which means you can't instantiate it directly; you have to create a derived type.  The main job of this control is to hook up an HTML element with some behaviors on the page, as XML script.  This class takes two generic parameters.  One is a TargetPropertiesBase-derived type (see below), and the other is a Control type (e.g. Panel).  This type specifies which kind of controls in the web designer that your extender will be available for.

The other class that you'll spend time working with is Microsoft.AtlasControlExtender.TargetPropertiesBase (we'll call this TPB), which is another abstract, generic class. ECB and TPB are the Yin and Yang of our Extender universe. An ECB instance has a collection of TPB's - one for each association between a server control and a behavior. So in the case of CascadingDropDown for example, there will be a TBP instance for each DropDownList.  This class has one generic parameter, which is (again) the type of controls (e.g. Panel) that you want your extender to be available for.

On this class is where you declare your managed object model.  A simple one would look like this:

[DefaultProperty("SomeValue")]

public class MyExtenderProperties : TargetControlPropertiesBase<WebControl>

    {

        [DisplayName("someValue")]

        public string SomeValue

        {

            get

            {

                return GetPropertyStringValue("SomeValue");

            }

            set

            {

                SetPropertyStringValue("SomeValue", value);

            }

        }

    }

The general lifecycle works like this.  The developer adds an extender to their ASPX page:

<ns:MyExtender ID="myExtender1" runat="server">

  <ns:MyExtenderProperties TargetControlID="Button1" SomeValue="Foo"/>

</ns:<yExtender>

When the page loads, this instantiates a server control that derives from ECB above.  It then instantiates a properties class (a TPB instance) and adds it to the extenders TargetProperties collection.

When the page renders, the ECB walks the properties of each TPB instance and generates XML for them.  So the page payload will get something like:

<script type="text/xml-script">

<references>

<add src="WebResource.axd?blahblahblahblahblahblah&blah"/>

</references>

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005" xmlns:myns="myns">

  <components>

    <control id="Button1">

      <behaviors>

        <myns:myBehavior someValue="Foo"/>

      </behaviors>

    </control>

  </components>

</page></script>

If you look at this XML and compare it to the above one, you'll see some similarities.  Both declare a connection to Button1, and a property called "SomeValue". If you weren’t using the toolkit, you’d have to write all of this by hand.  The JS gets down to the client via the WebResource.axd line.  The ECB does that for you automatically as well!

Let’s take a closer look at some of the features of the ECB:

RequiredScripts.  This is a ScriptReferenceCollection that lets you add a list of scripts that you want loaded before your behavior runs.  So if you’re writing a behavior that relies on something in the Atlas “UI Glitz” library, you’d add this code to your constructor:

public MyExtender(){                             

RequiredScripts.AddScriptReference(FrameworkScript.AtlasUIGlitz);

}

This can either be a FrameworkScript enum value or a string to URL of a JS file.  Note we’ve simplified this.  In the next drop, you’ll do this via a “RequiredScriptAttribute”, so rather than defining a constructor, you’ll just put “[RequiredScript(FrameworkScript.AtlasUIGlitz)]” on your class.  Moreover, you can pass the type of another extender here to cause the scripts for that extender to be loaded.  So say you want to write a behavior that leverages the ConfirmButton, you can add “[RequiredScript(typeof(ConfirmButtonExtender)]”. What's super cool about this is that it's recursive - you'll all the required scripts that ConfirmButtonExtender specifies as well.  Or else it wouldn't work.

 

ScriptPath.  This is a debugging helper property that really simplifies your script development.  Once you’ve got your ECB and TPB classes created, create an ASPX page and add them.  Copy your “MyBehavior.js” file next to that ASPX page, and then add the following (in bold) to your extender declaration:

<ns:MyExtender ID="myExtender1" ScriptPath="MyBehavior.js"  runat="server">

  <ns:MyExtenderProperties TargetControlID="Button1" SomeValue="Foo"/>

</ns:<yExtender>

This will cause the extender to load your script from the URL you give it instead of from the DLL, which is the default.  This allows you to debug and modify your script file without having to rebuild your extender.  When you’re done, don’t forget to copy this file back into your project.

RenderInnerScript.  This allows you to render extra script inside your behavior declaration.  Some behaviors allow setting of complex properties as sub-elements.  By overriding this method, you’ll get an opportunity to do that for each TargetProperties object associated with your extender:

protected override void

  RenderInnerScript(Microsoft.Web.Script.ScriptTextWriter writer,

MyExtenderProperties props)        {

    writer.WriteStartElement("someElement");               

    writer.WriteAttributeString("someValue");

    writer.WriteEndElement();              

}

ClientScriptResourceAttribute.  This isn’t a method on ECB but it’s related to it.  This is what associates your ECB instance with a script file.  Normally, it looks like this:

 

[ClientScriptResource("myns", "myBehavior", "MyProject.MyBehavior.js")]

 

But if you want to wrap an existing behavior in Atlas so that you can easily use it on the server-side, you just pass null for the namespace and drop the resource name:

 

[ClientScriptResource(null, "opacity")]

 

It’s very handy to do this so that you’ll never have to write any XML Script for extenders.  In this case you now have an extender which will hook an element up with the AtlasUIGlitz OpacityBehavior (note you’d need to add this to the RequiedScripts as well).

 

Now let’s look at what’s available on the TPB.  The class is pretty simple but it has several metadata (attribute) options that are very powerful:

 

EnsureValid.  When you create your TPB instance, you override this to make sure that the user has set all of the appropriate values.  See below for some improvements we’ve made for the next drop.

 

EnableClientState.  This enables client state transport between your extender and the class running on the client.  See the ClientState property below.  This defaults to false, so if you don’t set it, ClientState will do nothing.

 

ClientState.  This is a simple string property that will be made available to your running behavior instance on the client side.  So you could do something like this on the server side:

protected void Page_Load(object sender, EventArgs e)

    {

        MyExtender1.TargetProperties[0].ClientState = "hello";

    }

And on the client side, (in Javascript):

 

var state = this.getClientState(); // returns "hello"

 

It’s that simple.  There is a corresponding setClientState method on the Javascript side that you can call as well to change the value that the server-side receives.  These values persist only for the life of the page.  If the user refreshes or navigates away and back to the page, they start from their initial state again.


Now on to the attributes:

 

DefaultValueAttribute.  Put this on a TPB property to tell the framework what the default value is for a property.  Note this does not set that value, but is a comparison.  So, of you’ve got a string value, you would normally put [DefaultValue(null)] or [DefaultValue(0)] for an int.  The benefit of this is that it prevents the ECB from serializing out default values.  It sounds simple but it’s pretty important to get things working right.

 

DisplayNameAttribute.  This allows you to declare a different property name in your managed code from your client script code.  For example, you may want to have your managed class names start with an upper-case character, and your client script ones start with a lower case character.  Or you may be wrapping an existing behavior and prefer other names.  Note this attribute will be replaced by the ClientPropertyNameAttribute in the next drop.

  [DisplayName("someValue")]

  public string SomeValue { … }

IDReferenceAttribute.  This attribute tells the ECB that it references the ID of a control on the page.  So during rendering, the ECB will replace this value with the Client ID of the control.  Note this also tells the designer what kind of controls can be set into this property:

[IDReferenceProperty(typeof(WebControl))]

[DefaultValue(null)]

public string PopupControlID {…}

ResolveClientUrlAttribute.  Will be available in second release.  This tells the framework the property value for a given property is a client URL (e.g. “~/MyApp/SomeFile.jpg”) that should be mapped to a real URL during rendering.  This turns out to be handy for anything that specifies an image or a web service path.

[ResolveClientUrl()]

public string UncheckedImageUrl {…}

RequiredPropertyAttribute.  Will be available in second release.  This specifies that a given property declared on a TPB class is required.  I mentioned EnsureValid above.  Well this means you usually don’t need to write that code anymore.  If you just put these attributes on the properties that your behavior requires, the ECB serializer will check to see that each has a value and throw an exception if it doesn’t.

 

One last thing is on the Microsoft.AtlasControlExtender.Design.ExtenderControlBaseDesigner

class.  In most cases you won’t need to do anything with this class but there is one virtual member:

 

ExtenderPropertyName.  Override this to control the name of the property that shows up in the property grid for your extender when you click on the item that you want to extend.

protected override string ExtenderPropertyName{

   get            {

     "TheNameToShowInThePropertyGrid";

   }

}

Wow, that got long.  If you’re writing components, hopefully that will help.  Post comments for questions. 

 

I’m sure this will come up: when is the “second release” going to happen?  Well we’re currently trying to incorporate as much of the feedback we’ve gotten from customers, get Safari support working, and add a few new controls.  So with some luck you’ll see a release by the end of the month or thereabouts.

posted by sburke | 5 Comments
Filed Under:

Update on Toolkit compatibility with Safari

So I finally got a hold of a Mac I could use to try to figure out what the Safari issues are with the Toolkit.

What I found was that the toolkit classes didn't work at all.  Meaning, it wasn't that they were just buggy or something, they weren't even getting called.

After several hours of investigation, I finally figured out the core issue: if you register your class namespace as having any upper case characters at all, you don't get loaded on Safari.  All of the behaviors in the toolkit have the namespace "atlasControlToolkit", which means none of them load.

So to get one of the toolkit extenders working on Safari:

1) Open the .js file, scroll to the bottom and replace

Sys.TypeDescriptor.addType('atlasControlToolkit', ...);

with

Sys.TypeDescriptor.addType('atlascontroltoolkit', ...);

2) On that control, open the <control name>Extender.cs file, add a constructor, and add this call:

public ConfirmButtonExtender()
        {
            SuppressValidationScript = true;
        }

The reason you need step two is the base toolkit assembly also emits a badly-named namespace so you'll still get problems there if you're running in debug mode.  The validation script just tries to make sure that you've hooked everything up properly.  Note we'll be turning this off by default in our next drop - it's not super useful in most cases.

Even so, not all the controls work perfectly.  The list of controls I need to take a closer look at:

Major Issues

  • CascadingDropDown - doesn't appear to be calling back on the web service
  • HoverMenu - popup doesn't show
  • PopupControl - auto-close isn't working, and value isn't getting pushed to the text box

Issues:

  • TextBoxWatermark - doesn't clear on postback.  If you don't have text in there, you'll get the prompt text on the server-side as the control's text. 

The rest of the controls seem to work okay.  I'm shooting to get all of these things ironed out this week...

 

posted by sburke | 0 Comments

In case you see compile slowdowns upon adding Toolkit stuff to your website

A customer reported this problem.  If you're seeing this, it probably means you forgot to install the April CTP.  The problem is that the verson of Atlas that ends up in your bin directory doesn't match the one in your ..."program files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas" directory.  Your project has a update pointer to the older version but gets the newer version in the bin directory and this causes compile times to slow down.

Resolution steps:

1) Make sure you've got the April CTP in the directory above (it should have a date of 4/7/06)

2) Delete the .refresh files from your website\bin directory

posted by sburke | 1 Comments

Bertrand talks about Atlas and browser compat

I've seen a few mentions of how well the toolkit stuff does (or doesn't) work in Safari.  We chose to focus on IE and Firefox for our first release, not only for resource reasons (there's just three of us!) but because of some of the reasons mentioned in Bertrand's blog.  What we can make work in Safari (especially as Atlas support continues to improve, they're not even beta yet!), we will.

posted by sburke | 0 Comments

The Toolkit in action: Hooking up the CasdcadingDropDown

The "Atlas" Control Toolkit makes it super easy to add great usability features to your website. 

One of the things people regularly want to do is to create a "cascading" set of DropDownLists, where the value of each populates the values below.  The "Atlas" Control Toolkit contains a great extender to make this super easy to set up.  It does all of the population of the lists using an async call to a web service, which allows you to filter and cache the data on the server side and easily integrate it into your page. 

Go here to download and install the toolkit, and the Atlas April CTP if you don't already have it.  Once you've got it installed, you can see demos of all the controls in the toolkit.  Note that, like Atlas, this toolkit is an early version.  If you find issues, please report them in the Atlas Toolkit Forum so we can fix them for the next release.

But say I want to hook up a set of drop down lists.  First, I create a new Atlas Website, and add a reference to the toolkit assembly.  You'll find the assembly (called AtlasControlTookit.dll) in the "AtlasControlToolkit\bin" directory where you installed the tookit.  When prompted to replace the "Microsoft.Web.Atlas.DLL", choose 'No'.



In the default.aspx page and add some dropdowns to it:

   <div>

    Make: <asp:DropDownList ID="ddlMake" runat="server"/><br/>

    Model: <asp:DropDownList ID="ddlModel" runat="server"/><br/>

    Color: <asp:DropDownList ID="ddlColor" runat="server"/>       

    <br />       

    <asp:Button ID="Button1" runat="server" Text="Submit" />

   </div>


Now, at the top of your ASPX page, register a prefix for the reference to the tookit:

<%@ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit" TagPrefix="atlasToolkit" %>


And then add the extender itself:

   

<atlasToolkit:CascadingDropDown ID="CascadingDropDown1" runat="server">          

</atlasToolkit:CascadingDropDown>


At runtime, the extender will make callbacks to a web service we specify.  In that web service, it expects a WebMethod with the following signature (note that parameter names must match too!):

[WebMethod]

public CascadingDropDownNameValue[] GetColorsForModel(string knownCategoryValues, string category) 

The knownCategoryValues parameter will return a string containing the currently selected category values, as well as the category to retrieve values for.  For example, if the extender is populating the "Color" field, you will be passed the values for the "Make" and "Model" fields, as well as "Color" to specify the field to return values for.

The CascadingDropDown class has a helper method for unpacking the category values:

StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);


This method will return a StringDictionary containing the name/value pairs of the currently selected values.  So imagine you've got a database with tables for the Make (manufacturer), Model, and Color information, and you're accessing that database through a DataSet to which you've added methods for getting each set of values.

The web method to get the available colors for a given model would look like this:

[WebMethod]

public CascadingDropDownNameValue[] GetColorsForModel(

string knownCategoryValues, string category)  {

   

      StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

   

      int modelId;

   

      if (!kv.ContainsKey("Model") || !Int32.TryParse(kv["Model"], out modelId))

      {

           throw new ArgumentException("Couldn't find make.");

      }

   

      CarsTableAdapters.ColorTableAdapter adapter = new

CarsTableAdapters.ColorTableAdapter();

   

      Cars.ColorDataTable colorTable = adapter.GetColorsForModel(modelId);

   

List<CascadingDropDownNameValue> values = new

List<CascadingDropDownNameValue>();

   

      foreach (DataRow dr in colorTable) {

          values.Add(

new CascadingDropDownNameValue(

(string)dr["Color"],

dr["ColorID"].ToString()));

      }

   

      return values.ToArray();

}



So it's simple to return the values.  Now let's hook up our extender:

<atlasToolkit:CascadingDropDown ID="CascadingDropDown1" runat="server">

    <atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlMake"

Category="Make"

PromptText="Select a manufacturer"

ServicePath="CarsService.asmx"

ServiceMethod="GetCarMakes" />        

</atlasToolkit:CascadingDropDown>



If you look at this it's pretty simple.  TargetControlID specifies which control we're extending, in this case it's the drop down that specifies the manufacturer or "make" of the car.  PromptText specifies the text to show in the dropdown when no value is selected, and the ServicePath and ServiceMethod attributes tell the extender which web service to call to fetch it's values.

We can also do this hook up from the designer.  If you switch to design view, and select the "ddlModel" DropDownList, you can make these hookups in the property browser at design time:





Note the "ParentControlID" property which specifies which DropDownList is the "parent" for this one.  By setting these parent values, you can chain or "cascade" these values, and the CascadingDropDown extender will automatically manage setting, clearing, and loading the data for you. 

If you set up the ddlModel and ddlColor lists as well and go back to source view, you'll see:

        <atlasToolkit:CascadingDropDown ID="CascadingDropDown1" runat="server">

            <atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlMake"

Category="Make"

PromptText="Select a manufacturer"

ServicePath="CarsService.asmx"

ServiceMethod="GetCarMakes" />

          

            <atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlModel"

ParentControlID="ddlMake"

PromptText="Please select a model"

ServiceMethod="GetModelsForMake"

                  ServicePath="CarsService.asmx"

Category="Model" />

   

<atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlColor"

ParentControlID="ddlModel"

PromptText="Please select a color"

ServiceMethod="GetColorsForModel"

ServicePath="CarsService.asmx"

Category="Color"/>

          

        </atlasToolkit:CascadingDropDown>



Once you've completed your web service methods, your cascading drop down is complete!

Finally, in order for the values to be submitted, EventValidation needs to be disabled for the page.  EventValidation ensures that the values in each control match the values that were present when the page was rendered, but since these drop downs are populating on the client side, this is never true.  We’re working on a way to resolve this issue (I'm not happy about it either!), but please ensure that you understand this and validate the data appropriately in your post back when using this control.

posted by sburke | 10 Comments
Filed Under: ,
Attachment(s): pbrs.png

"Atlas" Control Toolkit available for download

Here.  Okay, yeah, it took a little longer than I'd hoped but we made some improvements in the meantime.

Check out all the details on the Atlas website, and we've created a forum for the toolkit as well.  The controls in the toolkit are basically preview quality.  They work at basic scenarios and we'll be releasing refreshes to deal with issues as we find them.  But what's more important to me is that they'll hopefully give you examples to start writing controls of your own. 

The toolkit includes full source for all of the controls, plus the sample website that demonstrates them.  The source is licensed under the Microsoft Permissive License which allows you to modify and reuse the code as you see fit.

The toolkit also includes a VSI that sets up an "Atlas Control Project" template on your machine (VB and C# versions) that will help you get started writing your own controls.

But the best part is yet to come.  We're doing something new and different here - this set of controls is more than just a add-on pack, it's going to be the kernel of a shared source project that we're starting around it.  Basically, my mission is to band together with our users (you!) and turn this tookit into the biggest, baddest set of web client UI extensions around.  We're still working out the details for how this is going to work but it shouldn't be too much longer.  Whether you are building an website that you want to bring to life or you want to hack out some radial JavaScript, this project will be the place for you.  Stay tuned.

In any case, start dreaming of the cool Atlas controls and extenders that you want to write and make it happen!

 

 

posted by sburke | 13 Comments
Filed Under: ,

Atlas talks at MIX and my new project

Shanku (Atlas/ASP.NET PUM) just finished giving his Atlas talk where he went through the major parts of Atlas and did a bunch of demos.

He also demo'd some of the stuff that my team has been working on.  I've been hinting about exactly what it is, and it's been now (cryptically) mentioned by Shanku and Scott in a few places.

I'm on a mission to make developing Atlas controls and extenders as easy as possible, as soon as possible.  I spent a few weeks fiddling with Atlas and I noticed a very common pattern:

Control Extender -> XML Script -> Behavior

Control Extenders, as I mentioned earlier, are server-side controls that hook up server-side UI controls with client side behaviors.  The glue between them is XML script that gets parsed on the client side and attaches the behavior to the running browser element.

ControlExtender derive from a class called ExtenderBase, and have a collection of objects that derive from TargetProperies.  From my last post, an extender for the ConfirmButton behavior might look like this in the ASPX:

<myns:ConfirmButtonExtender ID="cbe" runat="server">

<myns:ConfirmButtonProperties TargetControlID="Button1" ConfirmText="hello?" />

</myns:ConfirmButtonExtender>

So basically what's here is a class that derives from ExtenderBase that has a collection of type ConfirmButtonProperties. Each ConfirmButtonProperties object has a property called ConfirmText. 

The first thing I realized is that if you just named the properties in the ConfirmButtonProperties the same as the ones in your Javascript file, we could easily just walk that object and automatically generate the XML script for you.  Cool!  That's one less thing to learn, right?

That was just the start.  I also realized we could do a bunch of other stuff automatically.  Things like...

  • Knowing which properties referred to controls and then automatically fixing up the IDs at page-render time so they are client ID's in the XML Script (ASP.NET often encodes the ID of your server control to reflect nesting, etc, so "Button1" may not be "Button1" anymore when the browser sees it).
  • Automatically generating the script reference and packaging it up so you don't have to ship a JS file seperately from your ExtenderControl assembly.
  • Easily wrapping existing client behaviors so they are usable from the designer and you can program against them in the server-side model.
  • Encapsulate sending state back and forth between the client and the server so your client side script had some way of sending information back to the server in the event of a postback
  • Building "Atlas-aware" server side controls that render Atlas client behaviors behind the scenes for great UI experiences
  • Have your ExtenderControl be able to specify the scripts that it's dependant on and have those automatically downloaded before your control is instantiated so the user doesn't need to know/remember to set them up.

So it kind of grew from there.  The more we built the more cool ideas we had.  We started writing controls and adding functionality to the base classes, and before long, cranking out awesome Atlas controls/behaviors was a snap.

See, my last post was about how much I dig the Atlas Javascript framework.  So my goal here was two-fold:

1) To make the page-builder experience as familiar as possible for an ASP.NET developer

2) Cut out all the steps that I could so all you had to learn to get started was how to work in the Javascript framework.  No XML, no script references, none of that.  IJW - It Just Works.  You can learn the other stuff later, but you're not forced to learn it up front.

And now I've been having fun writing (eeeek!) Javascript and building behaviors that you can easily integrate into new or existing web pages.  We're going to give out source for the ones that we've built:

  • CollapsiblePanel - point this extender at a Panel control, give it a maximum and minimum size, and you'll get the roll-up/roll-down behavior on the client.  You can specify which control you "click" to make it collapse/expand, and it can expand horizontially or vertically.
  • HoverMenu - This is what Shanku demo'd today.  Basically, when you hover over control on the page, another control will be made visible and shown at a position of your choosing near your control.  Think of a normal GridView scenario where there is an Edit/Delete link by each row.  Now think of having those links appear as the user mouses-over each row.  You can also specify a CSS class to apply to the target when you over over it so it can highlight, etc.
  • TextboxWaterkmark - Some websites have greyed out "Type Here" text in textboxes when they're empty.  This extender does that.  Just tell it which textbox to show the text and what the text should be and it handles the rest.
  • ToggleButton - basically an image-checkbox, you can have better UI than plain checks in your application.  It's still a checkbox under the covers so you can databind to it, etc as usual.
  • ConfirmButton - this is the most demo I showed in my prior post.  Point it at a Button or LinkButton, set the text that you want to show, and it'll handle the rest.  If the user clicks "cancel", the click won't happen.
  • PopupControl - a hosting popup control that lets you have popup UI in your webpage.  For example, you can easily create a Date Picker by dropping a calendar control into this.
  • DragPanel - allows you to make a panel draggable and choose which control is the "handle" that users use to drag it around.
  • ReorderList - a server-side databound control that generates extenders at render-time and demonstrates how to create an Atlas-aware server side control.  In this case, it renders a list of items that the user can drag-drop reorder right in the browser.
  • CascadingDropDown - an extender that makes doing a sequence of drop down lists a snap (Make -> Model -> Color, for example).  It uses the Atlas web-service support to do the population of the lists asyncronously, and manages everything on the client side including clearing child items when a parent value changes (e.g. if you've selected "Ford", and "Mustang" and change to "Cheverolet", the Model field returns to "Please choose a model"), and actually disables fields that are farther down the chain which forces users to select in the right order.  It's super cool and can be hooked up to existing lists on the page.

In most of these cases you can also use the Javascript portion side as a standalone for non-ASP.NET scenarios as well.

We're working on getting this stuff packaged up so I can get it posted here soon and on the Atlas site before long.  As soon as that happens, I'll post a walkthrough of exactly how to use it so you can see first-hand why I've been having so much fun doing it.

UPDATED: Forgot CascadingDropDown...

posted by sburke | 6 Comments
Filed Under: , ,

Watching the keynote at MIX06

Sitting with Jordon and David from Code Project down here in Vegas watching the keynote at Mix 06 - mostly from BillG but some really cool stuff from the MySpace.com guys and the BBC, plus a cameo appearence by Tim O'Reilly doing a kind of an interview thing with Bill which is cool. 

I'm looking around though and noticing what a different crowd this is from the TechEd/PDCs that I'm used to.  A bit more varied, a bit better dressed maybe, but I'm impressed with the number of people that are down here.

A few months ago, when ScottGu told me about this show, he said "yeah, we're doing this show in Vegas but, man, the registration numbers aren't what we're hoping for."  He was worried that it was going to be a bust.  Well, no problem there - this place is packed!

And it turns out the Venitian is a pretty nice conference venue (imagine that).  It'll be interesting to see how things roll here.

Oh! The new Atlas site is up, and it looks great. 


 

posted by sburke | 0 Comments

What I like about Atlas: Behaviors

So I've been hacking away with Atlas now for the better part of two months.  As I got to playing with it, what I really focused in on was behaviors and control extenders.  You can really improve a website's experience without much pain by using them.

A behavior is a class written in Javascript that kind of attaches itself to a running element in the browser.

A control extender is an ASP.NET server-side control that helps you connect a control on the page to your behavior.  I'll talk about those later.

Behaviors are cool mostly because the Atlas script framework is super sweet.  I've always hated programming in script for a couple of reasons.  One of them hasn't gotten any better, so far at least, and that's that the tools experience around script is pretty weak.  No compiler, a minimal debugger, almost no Intellisense, etc.  The other issue is that it's just kind of scattered all over the place.  It's in random blocks through the HTML file, or in quotes as attribute values of tags or whatever.  Ick.

The script framework allows me to do away will all of that.  The framework puts some structure around the world, so even without the tooling, I'm able to do things much more effeciently.

Imagine a basic behavior that pops up a confirm box when you click a button.  To do this in script, it's something like:

<asp:Button ID="Button1" runat="server" Text="Button"

OnClientClick="return confirm('are you sure?');" />

Which isn't too bad but it's error prone, completely non-debuggable, and I have to sprinkle it all over my website, even though it's not a lot of code, and if there's something wrong with it (e.g. the above doesn't work in Mozilla), it's tough to change.  Of course, I could break the functionality out into a, er, function, but it doesn't greatly improve things.

Atlas gives me a nice way to handle this with a behavior.  Now, the following is a lot more code, but it's boilerplate, and it's maintainable and easily extensible if I decide I want to add more features.  The part that's specific to this guy is in bold:

Type.registerNamespace('MyNS');

MyNS.ConfirmButtonBehavior = function() {

MyNS.ConfirmButtonBehavior.initializeBase(this);

var _ConfirmTextValue;

var _clickHandler;

this.initialize = function() {

MyNS.ConfirmButtonBehavior.callBaseMethod(this, 'initialize');

// Initialize member variables

_clickHandler = Function.createDelegate(this, this._onClick);

// Attach event handlers

this.control.element.attachEvent("onclick", _clickHandler);

}

this.dispose = function() {

// Detach event handlers

if (_clickHandler) {

this.control.element.detachEvent("onclick", _clickHandler);

_clickHandler = null;

}

MyNS.ConfirmButtonBehavior.callBaseMethod(this, 'dispose');

}

this.getDescriptor = function() {

var td = MyNS.ConfirmButtonBehavior.callBaseMethod(this, 'getDescriptor');

td.addProperty('ConfirmText', String);

return td;

}

this._onClick = function() {

event.returnValue = window.confirm(_ConfirmTextValue);

}

this.get_ConfirmText = function() {

return _ConfirmTextValue;

}

this.set_ConfirmText = function(value) {

_ConfirmTextValue = value;

}

}

MyNS.ConfirmButtonBehavior.registerSealedClass('MyNS.ConfirmButtonBehavior', Sys.UI.Behavior);

Sys.TypeDescriptor.addType('MyNS', 'ConfirmButtonBehavior', MyNS.ConfirmButtonBehavior);

So, yeah, it's more code but it's nice and structured.  There's an initialize method where I set up my state, a dispose method where I tear it down, an _onClick method where I work my magic, and a couple of property accessors.  And if I want to add some functionality or some logic to run, I've got well-structured places to do it.  What's more is that this won't collide with other behaviors.  If you've got something else that you want to happen when a button is clicked, it will co-exist peacefully with this behavior.  Not so with the old script method.

So how do you use this on a web page?  Well that's a little trickier, and I'll give you a hint that extenders help.  But without extenders, here's how I hook it up:

1) Add a ScriptManager to my page

<atlas:ScriptManager ID="ScriptManager1" runat="server"/>

2) Add a control that's going to be the target of this behavior.  We'll add two.

<asp:Button ID="Button1" runat="server" Text="Button" />

<asp:Button ID="Button2" runat="server" Text="Button" />

3) Add the xmlscript to hook the things together.

<script type="text/xml-script">

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005" xmlns:MyNS="MyNS">

<references>

<add src="ConfirmButtonScript.js"/>

</references>

<components>

<control id="Button1">

<behaviors>

<MyNS:ConfirmButtonBehavior ConfirmText="Click Button1?"/>

</behaviors>

</control>

<control id="Button2">

<behaviors>

<MyNS:ConfirmButtonBehavior ConfirmText="Click Button2?"/>

</behaviors>

</control>

</components>

</page>

</script>

And boom, you've got your behavior hooked up, and you can hook that one behavior up to as many controls on the page as you like.  Much nicer.

Again, extenders make this experience much nicer.  I'll talk about those in a post soon.

 

 

 

 

posted by sburke | 5 Comments
Filed Under:

What am I working on?

I've been a "client guy" for my entire time here at Microsoft.  Windows Forms, WFC, the designers, all client code, most of it Win32 based.

The new team I've started is in the overall Frameworks organization (.NET Client, ASP.NET, the CLR, etc.) run by Scott Guthrie, and it's called The Agility Team.  Why the Agility Team?  It's not because we use Agile Software Developement, but we might try it out sometime.  It's because I want the team to stay fast, light, and agile, to be able to address needs as they come up and focus on new technologies coming out of Microsoft.

I blogged a little bit about it at my last work post on my (now personal) other blog, but in a nutshell the team's main function is to focus on new technologies, and to use them to build things that are similar to what our customers are going to build.  We're going to do it early so we have a chance to really drive deep feedback into the group building the technology, and we're going to do it transparently so users have a chance to see what we're up to and how we're using things. 

At the end of the day, it's about increasing product quality and driving adoption of the technologies, two things that are definitely related.

So I hired a great dev from MSN, and have a college hire on the way.  The first project that we've been working on is a set of ASP.NET "Atlas" sample controls and control extenders and a toolkit of helper classes that make writing those controls and extenders super-duper-easy.  With this set of classes and samples, the idea is to really help people get into using some of the great features Atlas provides and start cranking out some really cool controls and extenders.  It's turned into something pretty cool that I'm rather excited about, so it will be great when people get a chance to play with it.

We're still working on the nuts-and-bolts of exactly how this is going to work but keep an eye out for an announcement and bits next week at the Mix 06 Conference in Vegas.  I'll post details here too!

posted by sburke | 1 Comments
More Posts Next page »