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.