blog community

Welcome to blog community Sign in | Join | Help
in Search

Wouter van Vugt

This blog is no longer maintained and has moved

Developing a templated control designer in ASP.NET 2.0 - Part 4 / 5

Rendering the DuoView control is only the first step in building a more advanced designer. Although it is now possible to render either one of the templates, only the first template will actually get rendered. The next part consists of adding the ability to switch between templates using smart-tags. The design-time look of this new designer is displayed in Figure 1. Not only will the displayed template be selectable at design-time, an extra setting will be provided to enhance the look and feel of the control on the designer surface.

Figure 1. The smart-tagged designer used on the DuoView control

Some designers draw a table around the control they design. This makes the control easily selectable and visible when its templates are empty, for instance. The downside is the diminished similarity between the design-time and runtime edition of the control. Using smart-tags the user is presented with the ability to choose between enabling and disabling the rendering of an outer table. This new designer will require the addition of various blocks of code and the introduction of a new class. An introduction about how these classes interact is in order.

Introducing smart-tags

The process involved when using smart-tags is displayed in the following image

Figure 2. the smart-tag process

The process is initiated by the smart-tag panel. The panel queries the designer for a collection of DesignerActionLists. A DesignerActionList contains DesignerActionItems. The smart-tag panel will display each list in its own separate block. For each action item found in a list an editing control is provided by the smart-tag panel, the type of control corresponding with the type of setting provided by the DesignerActionItem. By using the control on the panel when it is shown at design-time the underlying DesignerActionItem will be called. The action item is connected to a method or property on the action list. The implementation usually changes the state of the designer or the control on the designer surface, but other custom actions (Mailing to a loved one?) can also be performed. When you want to use smart-tags on a control, you need to implement a class derived from DesignerActionList. This class will need to contain methods and properties to which a DesignerActionItem can bind. The DesignerActionItem class is provided by the framework. There are two subclasses, DesignerActionPropertyItem which is bound to a property on the DesignerActionList, and the DesignerActionMethodItem which can be tied to a method on the action list. The method item will cause the smart-tag panel to display a hyperlink. For property items an appropriate control is displayed for the Type of the property it is connected to.

Upgraded design-time rendering

To make the designer more visually appealing, a new property will be introduced to the designer. The DisplaySurroundingTable property will indicate which mode to draw the DuoView in at design-time, either with or without a surrounding table. Figure 3 displays the DuoView on the designer surface when being rendered without and with a table.

Figure 3. non-tabled and tabled display modes.

The DisplaySurroundingTable property uses the same designer state mechanism as implemented in the CurrentDisplayMode property.

Creating a DesignerActionList

The first part to implement for the smart-tag support is a subclass of DesignerActionList. Because it will change the state of the designer, a reference to the designer is passed in the constructor and stored for later use.

class DuoViewDesignerActionList : DesignerActionList
{
    public DuoViewDesignerActionList(
        SmartTaggedDuoViewDesigner designer)
        : base(designer.Component)
    {
        _designer = designer;
    }
}
Figure 4. defining an action list for the designer

The smart-tag panel needs to know about which settings are provided. It queries for this information by calling the GetSortedActionItems method. By overriding this method a custom list of actions is provided.

public override DesignerActionItemCollection GetSortedActionItems()
{
    DesignerActionItemCollection actions =
        new DesignerActionItemCollection();
    actions.Add(new DesignerActionPropertyItem("View",
        "Displayed view", String.Empty,
        "The view which is displayed in the DuoView control."));
    actions.Add(new DesignerActionPropertyItem("DisplayOuterTable",
        "Display surrounding table", String.Empty,
        "Indicates whether to display a surrounding table."));
    return actions;
}
Figure 5. accessing the action items in the action list

Two DesignerActionPropertyItems are used to indicate the available settings. Each one is connected to a property on the DesignerActionList, indicated by the first constructor parameter. The other parameters are used as the label, category and tool tip. The properties to which the DesignerActionItems are bound change the state of the designer

public bool DisplayOuterTable
{
    get
    {
        return _designer.DisplaySurroundingTable;
    }
    set
    {
        if (value != _designer.DisplaySurroundingTable)
        {
            _designer.DisplaySurroundingTable = value;
            _designer.UpdateDesignTimeHtml();
        }
    }
public DuoView.DisplayMode View{ get{...} set{...}}
}
Figure 6. defining design-time settings for the property bound actions

Attaching the DesignerActionList to the designer

Now that the first part of the smart-tag support is ready, it needs to be plugged in to the designer. Also, the new DisplaySurroundingTable property needs to be put to use. The following code elements will be added to the DuoViewDesigner class.

The custom DesignerActionList is tied to the designer through the ActionLists property. The smart-tag panel will use this property to retrieve it.

public override DesignerActionListCollection ActionLists
{
    get
    {
        DesignerActionListCollection actions =
            new DesignerActionListCollection();
        actions.AddRange(base.ActionLists);
        actions.Add(new DuoViewDesignerActionList_SmartTags(this));
        return actions;
    }
}
Figure 7. attaching the action list to the designer

Updating the rendering code

Now that the user can switch to displaying an outer table, the designer will need to take care of rendering that table. The GetDesignTimeHtml method provided in the previous chapter needs to be augmented to do so. Instead of returning the markup directly, it is optionally wrapped in a hard-coded table.

public override string GetDesignTimeHtml()
{
    string html = base.GetDesignTimeHtml();
    if (DisplaySurroundingTable)
    {
        StringBuilder htmlBuilder = new StringBuilder();
        htmlBuilder.Append(@"<table cellspacing=0 cellpadding=0 border=0 
        style=''display:inline-block''>');
        htmlBuilder.AppendFormat(@"<tr><td nowrap align=center 
            valign=middle style=''color:{0}; background-color:{1}; ''>
            {2}</td></tr>",
            ColorTranslator.ToHtml(SystemColors.ControlText),
            ColorTranslator.ToHtml(SystemColors.Control),
            ((DuoView)this.Component).ID);
        htmlBuilder.AppendFormat(@"<tr><td style=''vertical-align:top;'' 
        >{0}</td></tr>",
            html);
        html = htmlBuilder.ToString();
    }
    return html;
}
Figure 8. rendering code supplying an extra table

This finishes the third and pre-last designer for the DuoView, again by building upon the existing model and by adding a little code. The next designer will finish the design-time features by adding an editable region through which a template can be directly accessed without explicitly entering the edit mode. The smart-tag will be used to select which template to edit, in the same manner as it is now used to indicate the displayed template.

Published Thursday, September 15, 2005 8:54 AM by wouterv
Filed under:

Comments

 

TrackBack said:

September 16, 2005 9:06 AM
 

TrackBack said:

September 16, 2005 9:09 AM
 

TrackBack said:

September 16, 2005 9:11 AM
 

TrackBack said:

September 16, 2005 9:42 AM
 

TrackBack said:

September 16, 2005 9:46 AM
 

TrackBack said:

September 16, 2005 9:46 AM
 

Peter Kellner said:

Great Article! One question though. I'm trying to figure out how to populate a template programmatically. That is, have the Label control automatically stuffed into one of the templates without the user having to drag it in from the toolbox. How do I do that?

Thanks peter at peterkellner.net
August 13, 2006 5:36 PM
 

Wouter said:

HI Peter,

you can create a new class and have it implement ITemplate.

Like:

class MyDefaultTemplate : ITemplate
{
public void InstantiateIn(Control container)
{
Label label = new Label();
container.Controls.Add(label);
// for databound label only
label.DataBinding += new Eventhandler(BindLabel);

}

void BindLabel(object sender, EventArgs e)
{
Label label = (Label)sender;
Control namingContainer = DataBinder.GetContainer(label);
label.Text = DataBinder.Eval(namingContainer, "MyFieldInDataSource");
}
}

Forgive the compiler errors, this is some freeform code.

Hope it helps!

Wouter
August 14, 2006 11:03 AM
Anonymous comments are disabled

This Blog

Syndication

News


Add to Technorati Favorites
Powered by Community Server, by Telligent Systems