Results 1 to 3 of 3

Thread: Smart Tags (Tasks) in your UserControl / Custom control

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Smart Tags (Tasks) in your UserControl / Custom control

    Always wondered how you create the handy little Tasks (often called Smart-Tags) that allow you to change common properties with ease?


    Here is an explanation on how to create various types of Smart-Tags, including an example (VS2008).


    If you want to add Smart-Tags to your custom control, or your UserControl, you need to create a custom Designer class for that control.

    For the purpose of this 'tutorial', I will use a custom control that inherits from the TextBox control, without having any special custom functions. Therefore, it behaves just like any ordinary TextBox. I have called it customTextBox.
    vb.net Code:
    1. Public Class customTextBox
    2.     Inherits TextBox
    3.  
    4. End Class

    To even be able to use any Designer functions/methods etc, you first need to add a Reference to System.Design (right-click the solution icon in the Solution Explorer and choose Add Reference..., then choose System.Design in the list).


    Now it's time to start on our Designer class. Create a new Class and call it customTextBoxDesigner (or something equally descriptive).

    Let's first import a few important namespaces, and make our class inherit from the default ControlDesigner:
    (You can also inherit from the ParentControlDesigner for example, which allows your control to Parent other controls, like a Panel, Groupbox etc)
    vb.net Code:
    1. Imports System.Windows.Forms.Design
    2. Imports System.ComponentModel.Design
    3. Imports System.ComponentModel
    4.  
    5. Public Class customTextBoxDesigner
    6.     Inherits ControlDesigner
    7.  
    8. End Class


    Now, we need one last class, inheriting from the DesignerActionList. I always find it useful to have this class in the same file as the Designer class, so we can make it Friend instead of Public: you will not need this class outside of the Designer class so making it Friend is sufficient.
    Because we are inheriting from the DesignerActionList, this class requires a constructor (Sub New), something Visual Studio will tell you if you forget it.
    We will need a reference to our custom control in this last class, so it is useful to be able to pass our control as a reference when we create a New instance of this class. Therefore, we need the constructor to accept a component (IComponent) argument, which will hold our custom control.
    We then cast this component to our custom control and store it in a private reference variable (txt).
    We will also need a DesignerActionUIService reference to be able to Refresh our Smart-Tag panel when that is required.
    vb.net Code:
    1. Friend Class TextBoxActionList
    2.     Inherits DesignerActionList
    3.  
    4.     Private txt As customTextBox
    5.  
    6.     Private txt As customTextBox
    7.     Private designerActionSvc As DesignerActionUIService
    8.  
    9.     Public Sub New(ByVal component As IComponent)
    10.         MyBase.New(component)
    11.  
    12.         txt = DirectCast(component, customTextBox)
    13.         designerActionSvc = CType(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
    14.     End Sub
    15.  
    16. End Class

    Now, let's go back to our Designer class again. The DesignerActionList class we have just created merely creates the different items on our Smart-Tag panel (we have yet to do that), but we still need to tell the Designer class of our custom control that it should actually use these items.
    To do that, we need to Override the ActionLists property, and instead of returning the Mybase.ActionLists (which contain the default ActionListItems), we return a custom DesignerActionListCollection containing our custom DesignerActionList.
    There's not much to explain about this other than we need to make sure the ActionListCollection is not empty before returning it. If it is, we need to create a New instance of our collection:
    vb.net Code:
    1. Imports System.Windows.Forms.Design
    2. Imports System.ComponentModel.Design
    3. Imports System.ComponentModel
    4.  
    5. Public Class customTextBoxDesigner
    6.     Inherits ControlDesigner
    7.  
    8.     Private _actionListCollection As DesignerActionListCollection
    9.  
    10.     Public Overrides ReadOnly Property ActionLists() As System.ComponentModel.Design.DesignerActionListCollection
    11.         Get
    12.             If _actionListCollection Is Nothing Then
    13.                 _actionListCollection = New DesignerActionListCollection()
    14.                 _actionListCollection.Add(New TextBoxActionList(Me.Control))
    15.             End If
    16.  
    17.             Return _actionListCollection
    18.         End Get
    19.     End Property
    20. End Class

    The Designer class is now finished. Note that there is MUCH more you can do with a custom Designer class (see for example my WizardControl and my Custom TabControl in my signature), but if all you require is Smart-Tags, this is it.


    Let's go back to our DesignerActionList (which I've called TextBoxActionList class (should be in the same file).
    We still need to tell the designer which properties and methods should be in the Smart-Tag panel. This will obviously depend on your requirements, so I have added a few different examples in my attached project. I am only going to describe the process for one property and one method here though, since it is the same every time.

    You may have noticed from other Smart-Tags that there are different kinds of properties: there are textboxes you can change, there are checkboxes, comboboxes, Font selectors, etc, etc, etc. The great thing about this is, you don't need to worry about that at all! Visual Studio understands which type of 'control' (on the Smart-Tag panel) is required for each Type of your property. If you create a Boolean property, it will create a Checkbox. If you create a String property, a Textbox will appear. If you create a DockStyle property, a complete 'Dock control' will appear.

    The most common property of a TextBox is obviously its Text property, so we need a Property (of type String) that gets and sets the Text property of our customTextBox (txt):
    vb.net Code:
    1. Public Property Text() As String
    2.         Get
    3.             Return txt.Text
    4.         End Get
    5.         Set(ByVal value As String)
    6.             txt.Text = value
    7.         End Set
    8.     End Property
    (As I've said, if you require a Font property for example, just make it of type Font and you will get a button on the Smart-Tag panel that allows you to browse through Font styles.)

    Besides properties, you can also put methods (that will appear as a hyperlink) on the Smart-Tag panel. Clicking these will run a piece of code that can do whatever you want (such as change the size of a control, or more commonly Dock/Undock it into the parent container).

    The Dock/Undock method hyperlink on a Smart-Tag usually changes its text to "Undock in parent container." when the control is Docked, and to "Dock in parent container." when the control is Undocked. We will get to that later. For now, let's just create the method that will Dock or Undock our control. One thing is important to allow the text to change: we need to refresh the DesignerActionService (designerActionSvc.Refresh) otherwise the text won't change until you close and re-open the Smart-Tag panel.
    vb.net Code:
    1. Public Sub OnDock()
    2.         If txt.Dock = DockStyle.Fill Then
    3.             txt.Dock = DockStyle.None
    4.         Else
    5.             txt.Dock = DockStyle.Fill
    6.         End If
    7.  
    8.         designerActionSvc.Refresh(txt)
    9.     End Sub


    (Continued in next post....)
    Attached Files Attached Files

  2. #2

    Thread Starter
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Smart-Tags (Tasks) in your UserControl / Custom control

    Finally, we need to Override the GetSortedActionItems function that returns a collection of DesignerActionItems (the items on the Smart-Tag panel). Instead of returning the default collection, we create a new DesignerActionItemCollection, and add new Headers (New DesignerActionHeaderItem), properties (New DesignerActionPropertyItem and methods (New DesignerActionMethodItem). At the end, we return our new collection.

    But first, we need to determine if our Dock/Undock method needs to display either "Dock" or "Undock" in its display title. This is simple enough with a normal If/Else construction. Just save the desired text into a String, which you pass as the Display title to the DesignerActionMethodItem.

    The DesignerActionHeaderItems are easy enough: they only require one parameter, the displayName which is simply the name they will display on the Smart-Tag panel. These will be our categories, so take care to type them correctly.

    The DesignerActionPropertyItems need a few more parameters:
    - memberName: the name of the property you have created above.
    - displayName: the name that will be displayed on the panel.
    - category: the name (displayName) of the category (Header) you (may) have created. Leave this empty ("") to put it outside of any categories).
    - description: the description that will show in a ToolTip if you hover your mouse over this item.

    The DesignerActionMethodItems need one more parameter (the first one), namely the actionList property. You should pass the current DesignerActionList (Me) to this property.

    Finally, we return this new collection:
    vb.net Code:
    1. Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection
    2.         Dim str As String
    3.         Dim items As New DesignerActionItemCollection
    4.  
    5.         If txt.Dock = DockStyle.Fill Then
    6.             str = "Undock in parent container."
    7.         Else
    8.             str = "Dock in parent container."
    9.         End If
    10.  
    11.         'Add a few Header Items (categories)
    12.         items.Add(New DesignerActionHeaderItem("Category 1"))
    13.         items.Add(New DesignerActionHeaderItem("Category 2"))
    14.  
    15.         'Add the properties
    16.         items.Add(New DesignerActionPropertyItem("Text", "Text", "Category 1", "Gets or sets the Text of the customTextBox."))
    17.         items.Add(New DesignerActionPropertyItem("Font", "Font", "Category 1", "Gets or sets the Font of the customTextBox."))
    18.         items.Add(New DesignerActionPropertyItem("BackColor", "BackColor", "Category 1", "Gets or sets the BackColor of the customTextBox."))
    19.         items.Add(New DesignerActionPropertyItem("MultiLine", "Multi-line", "Category 1", "Gets or sets the Multi-line property of the customTextBox."))
    20.  
    21.         'Add the methods
    22.         items.Add(New DesignerActionMethodItem(Me, "OnClear", "Clear text", "Category 2", "Clears the text in the customTextBox."))
    23.         If txt.Multiline Then
    24.             items.Add(New DesignerActionMethodItem(Me, "OnMakeSquare", "Make a square", "Category 2", "Changes the width or height of the customTextBox to resemble a square."))
    25.             items.Add(New DesignerActionMethodItem(Me, "OnDock", str, "Category 2", "Docks or undocks the customTextBox in the parent container."))
    26.         End If
    27.  
    28.         'Return the ActionItemCollection
    29.         Return items
    30.     End Function
    (Note that I have added a few more items in this piece of code, which is straight from my example)

    We are almost finished! The last thing we need to do (the thing I always forget ) is to tell our custom control or UserControl to actually use our Designer class! To do this, we need to add a System.ComponentModel.Designer attribute at the top of our class, to which we pass the type of our custom Designer class as a parameter:
    vb.net Code:
    1. <System.ComponentModel.Designer(GetType(customTextBoxDesigner))> _
    2. Public Class customTextBox
    3.     Inherits TextBox
    4.  
    5. End Class


    If you now Build your solution, drop the customTextBox on your form, and click the little arrow in the top-right corner, the Smart-Tags should pop up!




    I have attached an example project (for VS2008 or higher), and in the next post I have posted the entire code for the Designer class (including the DesignerActionList class), so you shouldn't have any trouble incorporating this into your own control!

    Still, if you have any questions, suggestions, or otherwise, just leave me a message here and I'll try to see if I can help you.

    Enjoy it..!


    Code:
    Imports System.Windows.Forms.Design
    Imports System.ComponentModel.Design
    Imports System.ComponentModel
    
    Public Class customTextBoxDesigner
        Inherits ControlDesigner
    
        Private _actionListCollection As DesignerActionListCollection
    
        Public Overrides ReadOnly Property ActionLists() As System.ComponentModel.Design.DesignerActionListCollection
            Get
                If _actionListCollection Is Nothing Then
                    _actionListCollection = New DesignerActionListCollection()
                    _actionListCollection.Add(New TextBoxActionList(Me.Control))
                End If
    
                Return _actionListCollection
            End Get
        End Property
    End Class
    
    Friend Class TextBoxActionList
        Inherits DesignerActionList
    
        Private txt As customTextBox
        Private designerActionSvc As DesignerActionUIService
    
        Public Sub New(ByVal component As IComponent)
            MyBase.New(component)
    
            txt = DirectCast(component, customTextBox)
            designerActionSvc = CType(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
        End Sub
    
    #Region " Properties to display in the Smart-Tag panel "
    
        Public Property Text() As String
            Get
                Return txt.Text
            End Get
            Set(ByVal value As String)
                txt.Text = value
            End Set
        End Property
    
        Public Property Font() As Font
            Get
                Return txt.Font
            End Get
            Set(ByVal value As Font)
                txt.Font = value
            End Set
        End Property
    
        Public Property BackColor() As Color
            Get
                Return txt.BackColor
            End Get
            Set(ByVal value As Color)
                txt.BackColor = value
            End Set
        End Property
    
        Public Property MultiLine() As Boolean
            Get
                Return txt.Multiline
            End Get
            Set(ByVal value As Boolean)
                txt.Multiline = value
                designerActionSvc.Refresh(txt)
            End Set
        End Property
    
    #End Region
    
    #Region " Methods to display in the Smart-Tag panel "
    
        Public Sub OnClear()
            txt.Clear()
        End Sub
    
        Public Sub OnMakeSquare()
            If txt.Multiline Then
                If txt.Width >= txt.Height Then
                    txt.Height = txt.Width
                Else
                    txt.Width = txt.Height
                End If
    
                designerActionSvc.Refresh(txt)
            End If
        End Sub
    
        Public Sub OnDock()
            If txt.Dock = DockStyle.Fill Then
                txt.Dock = DockStyle.None
            Else
                txt.Dock = DockStyle.Fill
            End If
    
            designerActionSvc.Refresh(txt)
        End Sub
    
    #End Region
    
        Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection
            Dim str As String
            Dim items As New DesignerActionItemCollection
    
            If txt.Dock = DockStyle.Fill Then
                str = "Undock in parent container."
            Else
                str = "Dock in parent container."
            End If
    
            'Add a few Header Items (categories)
            items.Add(New DesignerActionHeaderItem("Category 1"))
            items.Add(New DesignerActionHeaderItem("Category 2"))
    
            'Add the properties
            items.Add(New DesignerActionPropertyItem("Text", "Text", "Category 1", "Gets or sets the Text of the customTextBox."))
            items.Add(New DesignerActionPropertyItem("Font", "Font", "Category 1", "Gets or sets the Font of the customTextBox."))
            items.Add(New DesignerActionPropertyItem("BackColor", "BackColor", "Category 1", "Gets or sets the BackColor of the customTextBox."))
            items.Add(New DesignerActionPropertyItem("MultiLine", "Multi-line", "Category 1", "Gets or sets the Multi-line property of the customTextBox."))
    
            'Add the methods
            items.Add(New DesignerActionMethodItem(Me, "OnClear", "Clear text", "Category 2", "Clears the text in the customTextBox."))
            If txt.Multiline Then
                items.Add(New DesignerActionMethodItem(Me, "OnMakeSquare", "Make a square", "Category 2", "Changes the width or height of the customTextBox to resemble a square."))
                items.Add(New DesignerActionMethodItem(Me, "OnDock", str, "Category 2", "Docks or undocks the customTextBox in the parent container."))
            End If
    
            'Return the ActionItemCollection
            Return items
        End Function
    End Class

  3. #3
    PowerPoster JuggaloBrotha's Avatar
    Join Date
    Sep 2005
    Location
    Lansing, MI; USA
    Posts
    4,286

    Re: Smart Tags (Tasks) in your UserControl / Custom control

    Talked to Nick this morning, for anyone who's looking for more info on this Nick did find this article explaining it a bit more Simplify UI Development: Custom Designer Actions in Visual Studio
    Currently using VS 2015 Enterprise on Win10 Enterprise x64.

    CodeBank: All ThreadsColors ComboBoxFading & Gradient FormMoveItemListBox/MoveItemListViewMultilineListBoxMenuButtonToolStripCheckBoxStart with Windows

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width