Adding Smart Tags to Windows Forms Controls

Adding Smart Tags to Windows Forms Controls

smart tag is a panel that displays next to a control and contains a list of commonly used properties. For example, in the Visual Studio (VS) editor, the Windows Forms DataGridView control uses a smart tag with the title “DataGridView Tasks” that displays a list of commonly used properties (see Figure 1). In .NET 2.0, developers can add smart tag features to their custom and user controls. This article walks you through a real world project that shows how to add your own smart tags to controls.

?
Figure 1: Smart Tag in Visual Studio: Here’s a look at the DataGridView control’s smart tag.

In this article, you’ll see how to create a custom date control. I initially built this control because a client specifically wanted an easy way to enter dates?without using the mouse to select a date. In addition, the client wanted the ability to customize the date display format?either numerically or alphabetically?to represent the month. On the surface this task looks easy to solve; simply add a couple of TextBox controls to the form and configure them to display day, month, and year accordingly. However, the client had numerous forms requiring date entry; therefore, a better solution was to create a user control that aggregates all the TextBox controls into one single control. The first part of this article discusses creating the user control, while the second part shows you how to add smart tag support to it.

Developing the User Control
Using VS 2005, create a new Windows Application project named SmartTag. This application will host the user control that you’ll see how to build in this article.

?
Figure 2: Design Mode: The figure shows the design surface of the user control with controls added to it.

Now, add a new Windows Control Library project to the existing solution. In Solution Explorer, right-click the SmartTag solution and select Add ( New Project?. Select the Windows Control Library template and name the project CustomDateControl. Click OK. The left portion of Figure 2 shows the default design surface of the user control (the default name is UserControl1.vb). Populate the design surface with three ComboBox controls as shown on the right side of Figure 2.

Set the properties of the three ComboBox controls with the values shown in Table 1.

Table 1. Use these values to set the properties of the three ComboBox controls.
Control Property Value
UserControl1 Size 230,32
cbbField1 AutoCompleteMode SuggestAppend
cbbField1 AutoCompleteSource ListItems
cbbField1 DropDownStyle DropDownList
cbbField2 AutoCompleteMode SuggestAppend
cbbField2 AutoCompleteSource ListItems
cbbField2 DropDownStyle DropDownList
cbbYear AutoCompleteMode SuggestAppend
cbbYear AutoCompleteSource ListItems
cbbYear DropDownStyle DropDownList

The first two ComboBox controls will display either the day or month (depending on the user’s configuration) while the third ComboBox control will display the year. Users can click the ComboBox control to select a date or simply type the date using the keyboard.

Editor’s Note: This article was first published in the July/August 2007 issue of CoDe Magazine, and is reprinted here by permission.

Programming the User Control
With the design of the user control completed, you can now start coding. Switch to the code behind file for the user control (UserControl1.vb) and add the following namespace:

   Imports System.ComponentModel

The System.ComponentModel namespace provides classes that are used to implement the run-time and design-time behavior of components and controls. In this case, you’ll be adding attributes to the control class and its properties to customize its behavior. You will see the effects of these attributes shortly.

Next, declare the Formats and Months enumerations to represent the format and months, respectively:

   Public Enum Formats      DDMMYYYY  '---e.g. 29 02 2006---      DDMmmYYYY '---e.g. 12 Jan 2006---      MMDDYYYY  '---e.g. 02 25 2006---      MmmDDYYYY '---e.g. Jan 15 2006---   End Enum   Public Enum Months      Jan = 1      Feb = 2      Mar = 3      Apr = 4      May = 5      Jun = 6      Jul = 7      Aug = 8      Sep = 9      Oct = 10      Nov = 11      Dec = 12   End Enum

Defining the Member Variables
Change the default class name from UserControl1 to DateControl and declare the member variables as shown below:

    _      Public Class DateControl      '---member variables---      Private _Format As Formats = Formats.DDMMYYYY      Private _Day As Integer      Private _Month As Integer      Private _year As Integer      Private _MinYear As Integer = 1918      Private _MaxYear As Integer = 2050      Private _DayControl As New ComboBox      Private _MonthControl As New ComboBox      '---event handler for error---       _         Public Event Err(ByVal str As String)   End Class
You use the ControlDesigner class to extend the design mode behavior of user controls.

Notice the following:

  • The control fires the Err event if a validation error occurs, providing the control with a way to communicate the error to the user.
  • The Category attribute causes the Err event to appear under the Date Settings category in the VS Properties window. The DescriptionAttribute specifies the message VS displays at the bottom of the properties window.
  • The DefaultEvent attribute indicates the default event handler for this control. When you drop this control on the design surface of a Windows Form, double-clicking it will automatically cause VS 2005 to insert stub code for the Err event handler.
  • The _DayControl and the _MonthControl reference the respective ComboBox controls representing the day and month.

Next, add a Format property to the class so users can select the date format. Depending on the format selected, the control uses the _DayControl and _MonthControl variables to reference the actual ComboBox controls representing the day and month. Also, when a user selects a format, the control calls the InitDates() method (defined shortly) to refresh the control dynamically to reflect the selected format:

    _   Public Property Format() As Formats      Get         Return _Format      End Get      Set(ByVal value As Formats)         _Format = value         Select Case Me.Format            Case Formats.DDMmmYYYY, Formats.DDMMYYYY               _DayControl = cbbField1               _MonthControl = cbbField2            Case Formats.MMDDYYYY, Formats.MmmDDYYYY               _DayControl = cbbField2               _MonthControl = cbbField1         End Select         _DayControl.BackColor = Color.White         _MonthControl.BackColor = Color.White         InitDates()      End Set   End Property

The Day property lets users set the day of the date individually, using a numeric value from 1 to 31. Notice that if the day value is set to an invalid value, the control raises the Err event:

    _   Public Property Day() As Integer      Get         Return _Day      End Get      Set(ByVal value As Integer)         If value >= 1 And value <= 31 Then            _Day = value            _DayControl.Text = _Day         Else            RaiseEvent Err("Day is out of range.")         End If      End Set   End Property

The Month property lets users set the month to a numeric value from 1 to 12. While it is similar to the Day property, you need to take special care when users select a format that displays the month alphabetically (such as Jan or Feb), because you must convert the numeric value of the month into its corresponding enumeration value:

    _   Public Property Month() As Integer      Get         Return _Month      End Get      Set(ByVal value As Integer)         If value >= 1 And value <= 12 Then            _Month = value            If Me.Format = Formats.DDMMYYYY Or _               Me.Format = Formats.MMDDYYYY Then                  _MonthControl.Text = _Month            Else               _MonthControl.Text = _                  [Enum].GetName( _                  GetType(Months), _Month)            End If         Else            RaiseEvent Err( _                "Month is out of range.")         End If      End Set   End Property

Creating the Year property is much more straightforward:

    _      Public Property Year() As Integer         Get            Return _year         End Get      Set(ByVal value As Integer)         _year = value         cbbYear.Text = _year      End Set   End Property

In addition to properties for setting the day, month, and year, the control has a [Date] (the square brackets are because Date is a reserved word in VB) property to let users set the date using the Date class:

    _   Public Property [Date]() As Date      Get         Try            Dim d As New Date( _               Me.Year, Me.Month, Me.Day)            Return d         Catch ex As Exception            Return Nothing         End Try      End Get      Set(ByVal value As Date)         Me.Day = value.Day         Me.Month = value.Month         Me.Year = value.Year      End Set   End Property

The MinYear and MaxYear properties set the first and last years to display:

    _   Public Property MinYear() As Integer      Get         Return _MinYear      End Get      Set(ByVal value As Integer)         _MinYear = value      End Set   End Property       _   Public Property MaxYear() As Integer      Get         Return _MaxYear      End Get      Set(ByVal value As Integer)         _MaxYear = value      End Set   End Property

As mentioned previously, the InitDates() method refreshes the control so it reflects the currently selected format:

   Private Sub InitDates()      '---day---      _DayControl.Items.Clear()      For i As Integer = 1 To 31         _DayControl.Items.Add(i)      Next      '---month---      _MonthControl.Items.Clear()      For i As Integer = 1 To 12         If Me.Format = _            Formats.DDMMYYYY Or Me.Format = _            Formats.MMDDYYYY Then               _MonthControl.Items.Add(i)         Else            _MonthControl.Items.Add( _               [Enum].GetName( _               GetType(Months), i))         End If      Next      '---year---      cbbYear.Items.Clear()      For i As Integer = Me.MinYear To Me.MaxYear         cbbYear.Items.Add(i)      Next      '---display the set date---      _DayControl.SelectedIndex = Me.Day - 1      _MonthControl.SelectedIndex = Me.Month - 1      cbbYear.Text = Me.Year   End Sub

The preceding method simply populates the ComboBox controls with the various dates so that the user can choose from them, and sets them to display the currently selected date.

Servicing the Events
When a user clicks the ComboBox control you need to set the day, month, or year correctly according to the selected format. You accomplish this by servicing the SelectedIndexChanged event for each of the three ComboBox controls (see Listing 1).

You must take special care for cases where the month is represented alphabetically?you need to convert the enumeration value to its corresponding numeric value.

When dealing with dates you must ensure that the date selected by the user is a valid one. For example, February never has more than 29 days, and only 28 days except in leap years. This control checks for date validity every time the ComboBox controls lose their focus. You can use the Date.DaysInMonth() method to find out the number of days in a particular month and year (see Listing 2).

?
Figure 3. ToolBox: The figure shows the process of adding a new control to the ToolBox.

If the selected date is invalid, the control displays a balloon message (using the ToolTip control).

Testing the Control
That's it! You can now test the control. Right-click the CustomDateControl project item in Solution Explorer and select "Build" to compile the user control into a DLL. After you have compiled the user control, add it to the ToolBox by right-clicking the "All Windows Forms" tab in the ToolBox, and then selecting "Choose Items?" (see Figure 3).

In the Choose Toolbox Items dialog box, click the Browse button and navigate to the binDebug folder of the CustomDateControl project. Select the CustomDateControl.dll, click Open, and then click OK. You should now be able to see the DateControl listed in the ToolBox.

Back in the SmartTag Windows application project, drag and drop the DateControl from the ToolBox onto the default Form1 (see Figure 4).

?
Figure 4. Placing a DateControl: This is how the DateControl looks when you drag and drop it onto the form.
?
Figure 5. DateControl Properties and Events: These views of the Properties window show the DateControl's properties and events.

Right-click the DateControl on Form1 and select Properties to view its properties. Figure 5 shows the various DateControl properties and events listed under the Date Settings category (you must select the Categorized view in the Properties window to view this).

?
Figure 6. Populating the Form: Here's a design-time view of the RadioButton controls for the sample form.

To test the control, add a GroupBox control to Form1 and populate it with RadioButton controls as shown in Figure 6. You can see the code for the various RadioButtons in Listing 3.

The code below shows some examples of how you can configure the DateControl user control programmatically.

   Private Sub Form1_Load( _      ByVal sender As System.Object, _      ByVal e As System.EventArgs) _      Handles MyBase.Load         '---e.g. 1---      With DateControl1         .Format = CustomDateControl.Formats.DDMMYYYY         '---display today's date---         .Date = Today      End With         '---e.g. 2---      With DateControl1         .Format = CustomDateControl.Formats.MmmDDYYYY         '---displays Sep 15 1991---         .Date = New Date(1991, 9, 15)      End With         '---e.g. 3---      With DateControl1         .Format = CustomDateControl.Formats.MMDDYYYY         '---displays 12 16 2006---         .Day = 16         .Month = 12         .Year = 2006      End With   End Sub

Press F5 to debug the Windows application. Figure 7 shows various views of the DateControl user control, while Figure 8 shows the balloon message the control displays if a user selects an invalid date.

?
Figure 7. DateControl Views: The figure shows how the RadioButton options affect the display of the DateControl user control.
?
Figure 8. Balloon Error Message: Here's a how the balloon error message looks if users select an invalid date.

Adding Smart Tags
Now that you have built your user control, you can add a smart tag to it. Adding a smart tag to the control allows developers to configure commonly used properties of the control without having to do so via the Properties window.

The first step is to add a reference to the System.Design.dll assembly to the CustomDateControl project. Right-click the CustomDateControl item in Solution Explorer and select Add Reference?. In the .NET tab, select the System.Design component and click OK.

Next, add the System.ComponentModel.Design namespace to UserControl1.vb using these two Imports statements:

   Imports System.ComponentModel   Imports System.ComponentModel.Design

Creating the Control Designer
Add a new class definition to the UserControl1.vb file and name the class DateControlDesigner. This class will inherit from the System.Windows.Forms.Design.ControlDesigner class:

   Public Class DateControlDesigner   Inherits _      System.Windows.Forms. _      Design.ControlDesigner   End Class

You use the ControlDesigner class to extend the design-mode behavior of your user controls. In this case, you want to display a smart tag for the user control. Add the following member variables and property:

   Public Class DateControlDesigner      Inherits _         System.Windows.Forms.Design.ControlDesigner      Private lists As _         DesignerActionListCollection      Public Overrides ReadOnly _         Property ActionLists() _         As DesignerActionListCollection            Get            If lists Is Nothing Then               lists = New _                           DesignerActionListCollection()               lists.Add(New DateControlActionList( _                  Me.Component))            End If            Return lists         End Get      End Property   End Class

The DateControlDesigner class shown above contains a member variable called lists that holds a list of DesignerActionList objects. The DesignerActionList class provides the base class for types that define a list of items used to create a smart tag panel. This variable will contain a list of items that will eventually appear in the smart tag. You do this by creating an instance of the DateControlActionList class. Define the DateControlActionList class as follows, adding the new class definition to UserControl1.vb:

   Public Class DateControlActionList      Inherits System.ComponentModel. _      Design.DesignerActionList         '---indicate whether to display       ' today's date---      Private _DisplayTodayDate As Boolean      '---reference to the user control       Private myDateControl As DateControl      '---reference to DesignerActionUIService      Private designerActionSvc As _         DesignerActionUIService = Nothing   End Class

The DateControlActionList class will create the list of designer action items available in the smart tag. Next, create the class constructor, which accepts a single argument?a reference to the user control:

   Public Sub New(ByVal component As _      IComponent)      MyBase.New(component)      Me.myDateControl = component      Me.designerActionSvc = _      CType(GetService(GetType( _         DesignerActionUIService)), _         DesignerActionUIService)   End Sub

Add a function named GetPropertyByName() to retrieve the various properties of the user control:

You cannot set the properties of a user control directly; instead, you set them using a proxy property (which, in this case, is returned by the GetPropertyByName() function).
   Private Function GetPropertyByName( _      ByVal propName As String) As _      PropertyDescriptor      Dim prop As PropertyDescriptor      prop = TypeDescriptor. _         GetProperties( _         myDateControl)(propName)      If prop Is Nothing Then         Throw New ArgumentException( _            "Invalid property.", propName)      Else         Return prop      End If   End Function

Next, you need to declare the various action list items in the smart tag as properties (see Listing 4). To display all these properties as items in the smart tag, you will need to add them to the DesignerActionItemCollection object. You accomplish this by using the GetSortedActionItems() function, which you need to override in this class. The GetSortedActionItems() function populates the smart tag with the list of designer action items and arranges them in the order you specify within this function (see Listing 5).

?
Figure 9. Smart Tag Items: The figure shows the association between smart tag items and the various parameters of the DesignerActionPropertyItem class.

Note that setting a value for the DisplayTodayDate property causes the smart tag to refresh; Specifically, you hide the Date designer action item if the DisplayTodayDate property is set to True and display it when the property is False.

Figure 9 shows the various items in the smart tag and the relationships with their corresponding properties.

Finally, to associate the user control with the control designer, you need to add the Designer attribute to the DateControl class:

    _   Public Class DateControl

Viewing the Smart Tag
To view the updated control, you need to rebuild the CustomDateControl project. Right-click the project item in Solution Explorer and select Rebuild. Now, if you examine the DateControl in Form1 (from the SmartTag project), you can click the arrow located on the top-right corner to display the smart tag (see Figure 10).

?
Figure 10. Smart Tag in Action: Here's the completed smart tag displaying the various control properties.
?
Figure 11. Setting the Date: Choosing to display today's date hides the "Set the initial date" item.

Try using the smart tag to set the various control properties. Observe that if you check the "Display today's date" checkbox, the "Set the initial date item" disappears (see Figure 11).

This article showed you how to define and use the various classes that associate a smart tag with a user control. As a control developer, consider incorporating smart tags in your controls to add value and simplify their use.

devx-admin

devx-admin

Share the Post:
Game Changer

How ChatGPT is Changing the Game

The AI-powered tool ChatGPT has taken the computing world by storm, receiving high praise from experts like Brex design lead, Pietro Schirano. Developed by OpenAI,

Apple's AI Future

Inside Apple’s AI Expansion Plans

Rather than following the widespread pattern of job cuts in the tech sector, Apple’s CEO Tim Cook disclosed plans to increase the company’s UK workforce.

AI Finance

AI Stocks to Watch

As investor interest in artificial intelligence (AI) grows, many companies are highlighting their AI product plans. However, discovering AI stocks that already generate revenue from

Web App Security

Web Application Supply Chain Security

Today’s web applications depend on a wide array of third-party components and open-source tools to function effectively. This reliance on external resources poses significant security

Thrilling Battle

Thrilling Battle: Germany Versus Huawei

The German interior ministry has put forward suggestions that would oblige telecommunications operators to decrease their reliance on equipment manufactured by Chinese firms Huawei and

iPhone 15 Unveiling

The iPhone 15’s Secrets and Surprises

As we dive into the most frequently asked questions and intriguing features, let us reiterate that the iPhone 15 brings substantial advancements in technology and

Game Changer

How ChatGPT is Changing the Game

The AI-powered tool ChatGPT has taken the computing world by storm, receiving high praise from experts like Brex design lead, Pietro Schirano. Developed by OpenAI, ChatGPT is known for its

Apple's AI Future

Inside Apple’s AI Expansion Plans

Rather than following the widespread pattern of job cuts in the tech sector, Apple’s CEO Tim Cook disclosed plans to increase the company’s UK workforce. The main area of focus

AI Finance

AI Stocks to Watch

As investor interest in artificial intelligence (AI) grows, many companies are highlighting their AI product plans. However, discovering AI stocks that already generate revenue from generative AI, such as OpenAI,

Web App Security

Web Application Supply Chain Security

Today’s web applications depend on a wide array of third-party components and open-source tools to function effectively. This reliance on external resources poses significant security risks, as malicious actors can

Thrilling Battle

Thrilling Battle: Germany Versus Huawei

The German interior ministry has put forward suggestions that would oblige telecommunications operators to decrease their reliance on equipment manufactured by Chinese firms Huawei and ZTE. This development comes after

iPhone 15 Unveiling

The iPhone 15’s Secrets and Surprises

As we dive into the most frequently asked questions and intriguing features, let us reiterate that the iPhone 15 brings substantial advancements in technology and design compared to its predecessors.

Chip Overcoming

iPhone 15 Pro Max: Overcoming Chip Setbacks

Apple recently faced a significant challenge in the development of a key component for its latest iPhone series, the iPhone 15 Pro Max, which was unveiled just a week ago.

Performance Camera

iPhone 15: Performance, Camera, Battery

Apple’s highly anticipated iPhone 15 has finally hit the market, sending ripples of excitement across the tech industry. For those considering upgrading to this new model, three essential features come

Battery Breakthrough

Electric Vehicle Battery Breakthrough

The prices of lithium-ion batteries have seen a considerable reduction, with the cost per kilowatt-hour dipping under $100 for the first occasion in two years, as reported by energy analytics

Economy Act Soars

Virginia’s Clean Economy Act Soars Ahead

Virginia has made significant strides towards achieving its short-term carbon-free objectives as outlined in the Clean Economy Act of 2020. Currently, about 44,000 megawatts (MW) of wind, solar, and energy

Renewable Storage Innovation

Innovative Energy Storage Solutions

The Department of Energy recently revealed a significant investment of $325 million in advanced battery technologies to store excess renewable energy produced by solar and wind sources. This funding will

Renesas Tech Revolution

Revolutionizing India’s Tech Sector with Renesas

Tushar Sharma, a semiconductor engineer at Renesas Electronics, met with Indian Prime Minister Narendra Modi to discuss the company’s support for India’s “Make in India” initiative. This initiative focuses on

Development Project

Thrilling East Windsor Mixed-Use Development

Real estate developer James Cormier, in collaboration with a partnership, has purchased 137 acres of land in Connecticut for $1.15 million with the intention of constructing residential and commercial buildings.

USA Companies

Top Software Development Companies in USA

Navigating the tech landscape to find the right partner is crucial yet challenging. This article offers a comparative glimpse into the top software development companies in the USA. Through a

Software Development

Top Software Development Companies

Looking for the best in software development? Our list of Top Software Development Companies is your gateway to finding the right tech partner. Dive in and explore the leaders in

India Web Development

Top Web Development Companies in India

In the digital race, the right web development partner is your winning edge. Dive into our curated list of top web development companies in India, and kickstart your journey to

USA Web Development

Top Web Development Companies in USA

Looking for the best web development companies in the USA? We’ve got you covered! Check out our top 10 picks to find the right partner for your online project. Your

Clean Energy Adoption

Inside Michigan’s Clean Energy Revolution

Democratic state legislators in Michigan continue to discuss and debate clean energy legislation in the hopes of establishing a comprehensive clean energy strategy for the state. A Senate committee meeting

Chips Act Revolution

European Chips Act: What is it?

In response to the intensifying worldwide technology competition, Europe has unveiled the long-awaited European Chips Act. This daring legislative proposal aims to fortify Europe’s semiconductor supply chain and enhance its

Revolutionized Low-Code

You Should Use Low-Code Platforms for Apps

As the demand for rapid software development increases, low-code platforms have emerged as a popular choice among developers for their ability to build applications with minimal coding. These platforms not

Cybersecurity Strategy

Five Powerful Strategies to Bolster Your Cybersecurity

In today’s increasingly digital landscape, businesses of all sizes must prioritize cyber security measures to defend against potential dangers. Cyber security professionals suggest five simple technological strategies to help companies

Global Layoffs

Tech Layoffs Are Getting Worse Globally

Since the start of 2023, the global technology sector has experienced a significant rise in layoffs, with over 236,000 workers being let go by 1,019 tech firms, as per data

Huawei Electric Dazzle

Huawei Dazzles with Electric Vehicles and Wireless Earbuds

During a prominent unveiling event, Huawei, the Chinese telecommunications powerhouse, kept quiet about its enigmatic new 5G phone and alleged cutting-edge chip development. Instead, Huawei astounded the audience by presenting

Cybersecurity Banking Revolution

Digital Banking Needs Cybersecurity

The banking, financial, and insurance (BFSI) sectors are pioneers in digital transformation, using web applications and application programming interfaces (APIs) to provide seamless services to customers around the world. Rising

FinTech Leadership

Terry Clune’s Fintech Empire

Over the past 30 years, Terry Clune has built a remarkable business empire, with CluneTech at the helm. The CEO and Founder has successfully created eight fintech firms, attracting renowned