Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Customizing User Controls with Smart Tag Feature

0.00/5 (No votes)
22 Jun 2009 1  
This article explains how to add Smart Tag feature to a user control.

Introduction

This article explains how to add a Smart Tag feature to a user control. As we all know, user controls are commonly used in Windows Forms applications for reusability purposes providing various functionalities across the project. The Smart Tag facility added to it will have an extra benefit to the developers. They could customize the user controls according to their needs in different forms in the project during design-time by setting various properties and behaviours. This article also demonstrates this concept with a sample and simple application describing the steps in building the necessary components required.

Designer Services

The .NET design-time architecture provides ways for customizing the behaviour and display of components and controls in design mode. It lets developers build customized design-time extensions for components and controls. Developers can provide custom design-time behaviour, value configuration interfaces, code generation for property initialization, and take advantage of services provided by the design-time environment.

Most of the custom components and controls are designable, which means they have settings that users can configure with a graphical user interface (UI) at design time. These settings usually affect instances of the component at run time. For example, add a reference to the assembly System.Design and import the System.ComponentModel.Design namespace. You can create smart tags or a custom designer for any Windows Forms control or component with types in this namespace.

Design-time Architecture

There are three primary design-time support providers: Designers, Type converters, and UI Type editors. I would quickly describe few components in the above architecture that pertain only to this article.

Attributes associate a type or type member with a class that extends design-time behaviour. For example, a DesignerAttribute associates a type with a designer.

A designer can customize the behaviour of a component at design time, including its appearance, initialization, and interaction with the user. A designer can add, remove, or replace properties listed in a property browser for a selected component. A designer can provide user-defined methods that can be linked to certain component events or executed from a custom menu command, or DesignerVerb.

In the System.ComponentModel.Design namespace, DesignerActionList class provides the base class for types that define a list of items used to create a smart tag panel.

Designer commands and the DesignerAction object model provide a generalized way for you to specify a set of actions for a component at design time. Users then access these actions from the design surface, typically by clicking on a component's smart-tag glyph () and selecting one of the offered actions from the smart-tag panel. This model unifies the various ways a designer can offer commands to users.

Smart Tags

The smart-tag feature enables components and controls to display context-sensitive information and commands to users. The smart tag can be thought of as a replacement for designer verbs, because you can choose to display a smart tag item in the smart-tag panel and also in the shortcut menu associated with a component or control.

Designer Command Classes such as DesignerVerb and DesignerActionItem allow us to expose the designer commands in the form of menu commands while developing components and controls.

DesignerAction Object Model

The following is the list of important classes that implement the DesignerAction object model.

  • DesignerActionItem: Represents a panel item on a smart-tag panel.
  • DesignerActionList: Defines a list of items used to create a smart-tag panel.
  • DesignerActionService: Establishes a design-time service that manages the collection of DesignerActionItem objects for components.
  • DesignerActionTextItem: Represents a static text item on a panel. Derives from DesignerActionItem.
  • DesignerActionPropertyItem: Represents a panel item that is associated with a property in a class derived from DesignerActionList. Derives from DesignerActionItem.
  • DesignerActionMethodItem: Represents a panel item that is associated with a method in a class derived from DesignerActionList. Derives from DesignerActionItem.
  • DesignerActionHeaderItem: Represents a static header item on a smart-tag panel. Derives from DesignerActionTextItem.

Walkthrough for a Sample Application: UserControl with SmartTag

Now, with this understanding of Design-time classes, let me proceed further in developing a Usercontrol that is attached with a SmartTag. In this application, we have a usercontrol with a list of the names of the cities in a listbox and the users may filter out the cities by typing few characters in the text provided in the Smart Tag panel command.

Users may also set the background and foreground color of the usercontrol with the menu commands found in the Smart Tag panel. Thus, the Smart Tag feature built in this usercontrol with three verbs to get/set the values of BackColor and ForeColor of the user control and the Text property of the label control inside it to filter out the names of the cities.

Step 1: Create a Windows Forms Application and add a usercontrol named MyControl to it.

Step 2: Add a label control to the usercontrol surface. Set its Name property to “label2” and Text property to “List of Cities starting with:”.

Step 3: Add another label named “label1”.

Step 4: Add a listbox control and call it as listBox1.

Step 5: Remove the VS generated code for the class MyControl and add the following code to define the usercontrol with required properties. Note that the class is attached with a Designer attribute:

[Designer(typeof(myControlDesigner))]
    public partial class MyControl : UserControl
    {
        public MyControl()
        {
            InitializeComponent();
        }
        public override Color BackColor
        {
            get
            {
                return base.BackColor;
            }
            set
            {
                base.BackColor = value;
            }
        }

        public override Color ForeColor
        {
            get
            {
                return base.ForeColor;
            }
            set
            {
                base.ForeColor = value;
            }
        }
        public string LabelText
        {
            get
            {
                return this.label1.Text;
            }
            set
            {
                this.label1.Text = value;
            }
        }
}

Step 6: Add the following code in the Load event handler of MyControl after declaring an array for storing a list of names of the cities:

string[] cities;
private void MyControl_Load(object sender, EventArgs e)
{
   cities = new string[] { "NewYork", "Mumbai", "Belgrade", 
	"Los Angeles", "Chennai", "New Delhi", "Madrid", "Chicago",
	"Las Vegas", "Bangalore", "Sydney", "Melbourne", "Beijing", 
	"Calcutta", "Milan", "Austin", "Brisbane" };
}

Step 7: In the TextChanged event handler for the label1 control, add the following code that filters the names of the cities and populate the list box. It uses a LINQ query on the cities array and filters the names that start with the typed characters in the Smart Tag Panel. It is to note that the label1 is updated when the LabelText property of Mycontrol is changed.

        private void label1_TextChanged(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            IEnumerable filtered =
                           from a in cities
                           where a.StartsWith(label1.Text)
                           orderby a
                           select a; 
            if (filtered.Count() > 0)
                listBox1.Items.AddRange(filtered.ToArray());
        }

Step 8: Now, ControlDesigner class must be defined for MyControl as specified in the attribute in Step 5. This class myControlDesigner is attached with the PermissionSet attribute as it requires a full permission to access Smart Tag features.

[System.Security.Permissions.PermissionSet
	(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public class myControlDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        private DesignerActionListCollection actionLists;

        // Use pull model to populate smart tag menu.
        public override DesignerActionListCollection ActionLists
        {
            get
            {
                if (null == actionLists)
                {
                    actionLists = new DesignerActionListCollection();
                    actionLists.Add(new myControlActionList(this.Component));
                }
                return actionLists;
            }
        }
    }

Step 9: The following code creates a list of Smart Tag menu actions/commands for the usercontrol as specified in its constructor. The DesignerActionList class is inherited and the methods are implemented to created Smart Tag items.

public class myControlActionList : System.ComponentModel.Design.DesignerActionList
    {
        private MyControl  colUserControl;

        private DesignerActionUIService designerActionUISvc = null;

        //The constructor associates the control with the smart tag list.
        public myControlActionList(IComponent component)
            : base(component)
        {
            this.colUserControl = component as MyControl;

            // Cache a reference to DesignerActionUIService, 
	   // so the DesigneractionList can be refreshed.
            this.designerActionUISvc = GetService(typeof(DesignerActionUIService)) 
		as DesignerActionUIService;
        }

.....
.....
        // Implementation of this abstract method creates smart tag  items, 
        // associates their targets, and collects into list.
        public override DesignerActionItemCollection GetSortedActionItems()
        {
            DesignerActionItemCollection items = new DesignerActionItemCollection();

            //Define static section header entries.
            items.Add(new DesignerActionHeaderItem("Appearance"));

            items.Add(new DesignerActionPropertyItem("BackColor",
                                 "Back Color", "Appearance",
                                 "Selects the background color."));
            items.Add(new DesignerActionPropertyItem("ForeColor",
                                 "Fore Color", "Appearance",
                                 "Selects the foreground color."));
            items.Add(new DesignerActionPropertyItem("LabelText",
                                 "Label Text", "Appearance",
                                 "Type few characters to filter Cities."));
            return items;
        }

Step 10: Build the project.

Step 11: Open Form1 designer and drag the usercontrol MyControl” in the toolbox to the designer surface and see Smart Tag working smoothly.

Note

The complete code for creating a usercontrol with smart tag explained in this sample application is available for download along with this article. You may add the file MyControl.cs file to any Windows Forms application and add reference to System.Design assembly before building the project. Place the usercontrol in any form and see Smart Tag features working for you.

Conclusion

Smart tags are menu-like user interface (UI) elements that supply commonly used design-time options. Most of the standard components and controls provided with the .NET Framework contain smart tag and designer verb enhancements. This article showed you how to add smart-tag support to user controls so that they can be utilized well in Windows Forms applications.

History

  • 9th June, 2009: Initial post
  • 22nd June, 2009: Added source code

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here