DevCity.NET - http://devcity.net
Adding Mnemonics (Short Cut Keys) to Your Controls
http://devcity.net/Articles/136/1/article.aspx
Chris Manning
I work as a professional .NET developer specializing in the areas of Windows Applications, Web Applications, and ADO.NET. I spend a good majority of my free time helping developers learn the .NET framework at vbCity and was recently awarded the Microsoft Visual Developer, Visual Basic MVP award. 
by Chris Manning
Published on 3/11/2005
 

Part 1 of a Multi-Part Series on Control Design. This article shows you how to add Mnemonics (shortcut keys) to a Custom Control. This is question I see quite a bit. There isn’t much out there on it.Web searches don’t turn up very much, and the experts on this kind of stuff seem to hold it pretty close.My own quest to learn this was frustrating to say the least.I had to piece and part little clues together until I figured it out.


The Core Class

Lets get started.

 

For this example we’re going to use a custom button control.  The buttons you see in most commercially available applications usually use Mnemonics and have short cut keys, so this will hit close to home and should be pretty easily understood by all, from the rookie programmer to some of the more experienced developers out there.

 

I’m not going to spend too much time on this part, but in a nut shell here is our core button class.  It’s inherited from a UserControl.  Make sure to add a reference to the System.Design.dll.

 

Imports System

Imports System.ComponentModel

Imports System.CompoenetModel.Design

Imports System.Drawing

Imports System.Drawing.Design

Imports System.Drawing.Drawing2D

Imports System.Windows.Forms.Design

 


<DEFAULTEVENT("CLICK"), DefaultProperty(?Text?)>_

Public Class MyBasicButton

            Inherits System.Windows.Forms.UserControl

           

            +[Windows Generated Code]

 


           

            Protected Overrides Sub OnPaint(ByVal e as PaintEventArgs)

                        Dim g as Graphics = e.Graphics

                        g.SmoothingMode = SmoothingMode.AntiAlias

 

                        PaintBorderAndText(g)

 

                        MyBase.OnPaint(e)

            End Sub


            Private Sub PaintBorderAndText(ByVal g as Graphics)

                        Dim rect as New Rectangle(0, 0, Me.Width – 1, Me.Height – 1)

                        Dim rectf as New RectangleF(0, 0, Me.Width, Me.Height)

                        Dim sf as New StringFormat()

 

                        sf.Alignment = StringAlignment.Center

                        sf.LineAlignment = StringAlignment.Center

                        sf.HotKeyPrefix = System.Drawing.Text.HotKeyPrefix.Show

                        sf.Trimming = StringTrimming.EllipsesCharacter

                        sf.FormatFlags = StringFormatFlags.NoWrap

 

                        Dim b as Brush

 

                        ‘Draw the border

                        g.DrawRectangle(New Pen(Color.Black), rect)

 

                        Select Case m_State

                                    Case ButtonState.None

                                                b = New SolidBrush(Color.Black)

                                    Case ButtonState.Over

                                                b = New SolidBrush(Color.Blue)

                                    Case ButtonState.Clicked

                                                b = New SolidBrush(Color.Red)         

                        End Select

 

                        g.DrawString(m_Text, Me.Font, b, rectf, sf)

            End Sub


            Protected Overrides Sub OnMouseEnter(ByVal e as EventArgs)

                        MyBase.OnMouseEnter(e)

                        m_State = ButtonState.Over

                        Invalidate()

            End Sub


            Protected Overrides Sub OnMouseLeave(ByVal e as EventArgs)

                        MyBase.OnMouseLeave(e)

                        m_State = ButtonState.None

                        Invalidate()

            End Sub


            Protected Overrides Sub OnMouseDown(ByVal e as MouseEventArgs)

                        MyBase.OnMouseDown(e)

                        m_State = ButtonState.Clicked

                        Invalidate()

            End Sub


            Protected Overrides Sub OnMouseUp(ByVal e as MouseEventArgs)

                        MyBase.OnMouseUp(e)

                        Select Case m_State

                                    Case ButtonState.Clicked

                                                m_State = ButtonState.Over

                                    Case ButtonState.Over

                                                m_State = ButtonState.None

                        End Select

                        Invalidate()

            End Sub


            Protected Overrides Sub OnMove(ByVal e as EventArgs)

                        MyBase.OnMove(e)

                        Invalidate()

            End Sub


            Protected Overrides Sub OnResize(ByVal e as EventArgs)

                        MyBase.OnResize(e)

                        Invalidate()

            End Sub


            Private m_Text as String

<DESIGNERSERIALIZATIONVISIBILITY(DESIGNERSERIALIZATIONVISIBILITY.VISIBLE), color="#0000ff" Browsable(True)> _

            Public Overloads Overrides Property Text() as String

                        Get

                                    Return m_Text

                        End Get

                        Set (ByVal value as String)

                                    m_Text = value

                                    Invalidate()

                        End Set

            End Property


            Private m_State as ButtonState = ButtonState.None

 

            Public Enum ButtonState as Integer

                        None = 0

                        Over = 1

                        Clicked = 2

            End Enum

End Class

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   So that’s the basic class.  As it stands right now, you should be able to compile the library, add it to your toolbox and a form and run the application.  The text should change colors during the mouse events of the button.  Nothing fantastic, but functional. 

 

   However, stop the debugging on the application and in the Text property type

“&Button”.  The “B” in button should be underlined.  Now run the project again and try to use the ALT + B keys.  Nothing happens right?

 

 

Adding the Mnemonics

Now to the core of this article;  Implementing Mnemonics in Custom Controls.

 

First we need to Implement an Interface.  So in your button class code, right after the Inherits System.Windows.Forms.UserControl, add

 

 Implements IButtonControl

 

There are now three(3) subsequent Subs / Functions we need to implement and one(1) Property.

 

If you’re like me, you try to keep the properties with the properties, the subs with the subs, etc.. In a class, however you can add these anywhere in the class.

 

First let's implement the NotifyDefault  Sub.  Nothing will actually happen here, but we have to add it to satisfy the "Implements IButtonControl"

 

 Public Sub NotifyDefault() Implements IButtonControl.NotifyDefault

            ‘Nothing Happens Here

End Sub

 

Next we’ll implement the DialogResult property.  The DialogResult property is like the dialog result property for any type of form, button, messagebox, open file dialog…anything.  It simply supplies the UI with a corresponding result for certain actions.

 

Private m_DialogResult as DialogResult

Public Property DialogResult() as DialogResult Implements IButtonContro.DialogResult

            Get

                        Return m_DialogResult

            End Get

            Set (ByVal value as DialogResult)

                        If [Enum].IsDefined(GetType(DialogResult), value) Then

                                    m_DialogResult = value

                        End If

            End Set

End Property

We now need to Implement the PerformClick method.  This is what allows the Mnemonic call to perform any actions associated with the OnClick method and the subsequent Click Event.

 

 Public Sub PerformClick() Implements IButtonControl.PerformClick

            Me.OnClick(EventArgs.Empty)

End Sub

 

And last but not least, the Function that does it all:-  ProcessMnemonic.  This is the function that determines which key combinations are being pressed while the UI the control is on is active.  .NET has a couple of built in functions that help us determine two things.

  1. Is the key that’s being pressed the Key that we want to process and therefore perform our actions.
  2. Is there a control key that’s being held.  Control keys are keys like Alt, Ctrl, Return, etc.

 Public Overrides Function ProcessMnemonic(ByVal c as Char) as Boolean

            If (Control.IsMnemonic(c, Me.Text) and (Control.ModifierKeys = Keys.Alt)) Then

                        PerformClick()

                        Return true

Else

            Return False

End If

End Function

 

And that’s it.  You should now be able to recompile your control. Add it to a form, run the form and press “Alt + ‘YourMnemonicKey’”.  Barring you have something in the Click event of the control, that event should fire.