Friday, December 19, 2008

Writing Smart Tags for Windows as well as Web Controls to show help and about.

What are Smart Tags

Smart tags support was introduced in VS 2005.They helps us to do configuration of custom controls very easily in both Windows forms and Web.They also provide access to frequently used properties as well as to most important ones.

How to use smart tags

If a control is enabled with smart tags ,it will get the smart tag button at top right when we select the same in Visual Studio editor.A click on that button will show the smart tags.The button visually looks like an arrow towards right.

SmartTagOnWinForms

Creating smart tags for our own custom controls.

Usually smart tags are used to edit control properties or to configure the control itself.Here I am going to show a simple one in both ASP.Net and Windows forms which shows about and help boxes on smart tag click.

The solution contains 5 projects

  • DemoWebControlLibrary : A asp.net control library project holds the custom web control named "DemoWebControl"
  • DemoWindowsFormsControlLibrary: Contains the custom windows forms control named "DemoWindowsFormsControl"
  • DemoWebApplication & DemoWindowsFormsApplication: Hosts the DemoWebControl and DemoWindowsformsControl respectively
  • DemoSmartTags : Class library contains the smart tag implementation for both Web and Windows forms controls.

prjstruct

There is no need to talk about the controls library project and application projects which hosts them.So lets talk about the DemoSmartTags project.

That project contains 2 windows forms named "AboutForm" and "HelpForm".They are nothing but normal windows forms in which we are displaying the contents.

Another 2 main files / classes are WebControlDesigner and WindowsFormsControlDesigner.They are inherited from System.Web.UI.Design.ControlDesigner and System.Windows.Forms.Design.ControlDesigner respectively and are playing an important role in showing the smart tags.

Both these classes overrides a property called DesignerActionListCollection which is a collection of different actionlists.

public override DesignerActionListCollection ActionLists
{
get
{
if (actionLists == null)
{
actionLists = new DesignerActionListCollection();
actionLists.Add(new ControlActionList(this));
}
return actionLists;
}
}

Here the ControlActionList is same for both windows forms and web controls.This class defines the actual smart tags and add to the collection.

public class ControlActionList : DesignerActionList
{
ComponentDesigner _ComponentDesigner;

public ControlActionList
(ComponentDesigner comp)
: base(comp.Component)
{
_ComponentDesigner = comp;
}

}

Below is the code which creates action items or smart tags and associates to the designer.

public override DesignerActionItemCollection GetSortedActionItems()
{
DesignerActionItemCollection col = new DesignerActionItemCollection();
DesignerActionMethodItem helpItem = new DesignerActionMethodItem(this, "ShowHelp", "Help");

col.Add(helpItem);
DesignerActionMethodItem aboutItem = new DesignerActionMethodItem(this, "ShowAbout", "About");

col.Add(aboutItem);
return col;
}

Now it is surprising.Which is the handler that handles the click event? We need to have methods named "ShowHelp" and "ShowAbout".The runtime will automatically call those methods up on click.Not getting why implementation is like this which uses reflection..Strange...


public void ShowHelp() {
ShowForm(newHelpForm());
}

public void ShowAbout() {
ShowForm(newAboutForm());
}


We can't directly show the forms here.We have to use IUIService interface to accomplish the task.

void ShowForm(Form form)
{
IUIService service = (IUIService)_ComponentDesigner.Component.Site.GetService(typeof(IUIService));
if (service != null)
{
service.ShowDialog(form);
}
}
 

We have completed creating the designer and smart tags.Now we have to associate these designers to the respective web and windows forms controls.


Use the Designer attribute to do the same.

[Designer(typeof(WebControlDesigner))]
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class DemoWebControl : WebControl
{}

[Designer(typeof(WindowsFormsControlDesigner))]
public partial class DemoWindowsFormsControl : UserControl
{}

Now compile and open the hosting form or page in designer.Create instance of the control and pops up the smart tags.


Sample can be located here.

No comments: