Question Adding a list of all System.Windows.Forms.Keys to a ComboBox?

ccman32

New member
Joined
Jul 22, 2013
Messages
1
Programming Experience
1-3
Hello,

lets say for example i want to let the program play a .wav sound with My.Computer.Audio.Play by pressing a key.
I already have the function to register key presses and i want to give the user the choice for which hotkey he wants to press to play the sound.
Because there are some weird keys in System.Windows.Forms.Keys like ZOOM, Snapshot, Volume up/down ... i sorted these ones out and added the other ones everyone has on a normal keyboard into a list i added to the combobox items of the combobox in the form.
My question is:
How can i convert the combobox item strings of the keys into the actual object names of the keys like Keys.Escape or Keys.Delete so that i can use them like that in the program?
The method for detecting keypresses i use only accepts objects of the type System.Windows.Forms.Keys so i can't just code it like:
VB.NET:
If GetKeyPress(ComboBox1.text) Then
...
End If
Any ideas?
 
Hi,

The answer is, is that you DO NOT add TEXT to the ComboBox, but you add the Actual Key Object instead. When you do it this way the default ToString method of the Key is used to display the Text Value of the Key in the ComboBox and once selected you can then use DirectCast to cast the selected item in the ComboBox back to a Key Object for use in your project. i.e:-

VB.NET:
Public Class Form1
 
  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    ComboBox1.Items.Add(System.Windows.Forms.Keys.R)
    ComboBox1.Items.Add(System.Windows.Forms.Keys.Up)
    ComboBox1.Items.Add(System.Windows.Forms.Keys.F1)
  End Sub
 
  Private Sub ComboBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
    Dim selectedKey As System.Windows.Forms.Keys = DirectCast(ComboBox1.SelectedItem, System.Windows.Forms.Keys)
    MsgBox(selectedKey.ToString)
  End Sub
End Class

Hope that helps.

Cheers,

Ian
 
In reality what you need to do is construct a list from the Keys enum that you can bind to the combobox:

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim KeysValues As Array = [Enum].GetValues(GetType(Keys))
        Dim KeysDictionary As New Dictionary(Of String, Keys)

        For Index As Integer = 0 To KeysValues.Length - 1
            Dim Value = KeysValues.GetValue(Index)
            If Not KeysDictionary.ContainsKey(Value.ToString) Then KeysDictionary.Add(Value.ToString, Value)
        Next

        ComboBox1.DataSource = KeysDictionary.Values.ToList
    End Sub


The reason for the dictionary is that there are many repeats in this particular enum, otherwise it could have been a simple Array(Of Keys):

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ComboBox1.DataSource = [Enum].GetValues(GetType(Keys))
End Sub
 
Last edited:
I think Herman has overcomplicated things somewhat. All you need to bind is this:
ComboBox1.DataSource = [Enum].GetValues(GetType(Keys))
You'll the result of calling ToString on each Keys value in the list anyway. The SelectedItem and SelectedValue will then be the Keys value itself, so you simply cast it as such.
 
Having read post #1 more carefully, I would now recommend something like this:
Dim keysToExclude = {Keys.Zoom, Keys.Snapshot}

ComboBox1.DataSource = [Enum].GetValues(GetType(Keys)).Cast(Of Keys).Except(keysToExclude).ToArray()
Again, the SelectedItem itself will then be a Keys value so just use DirectCast on it.

This code probably warrants some explanation. The GetValues call gets an Array containing all the Keys values. The Cast call exposes the contents of that Array as Keys values rather than Object references. The Except call filters that list by removing items that also appear in another list and then the ToArray call puts that filtered list into a Keys array in order to support data-binding.
 
Oh and there's no real "weird" key, these are keys that can be setup by the OS. For example Keys.Zoom represents whatever key you have bound to Zoom in Windows.

EDIT: The problem with your approach jmc is that you still end up with all the doubles in the enum. The keysToExclude approach is good however, I would tag the .Except method to the end of my datasource assignment in my first example. You also don't need to cast anything, the .Items collection of the combobox has references to the undelying Keys value.
 
Last edited:
The problem with your approach jmc is that you still end up with all the doubles in the enum.
I don't really see that that's an issue. If there are two values in the enumeration that have the same numeric value then just let the user select either of them and they will then get what they expect.
You also don't need to cast anything, the .Items collection of the combobox has references to the undelying Keys object.
You certainly do need to cast if, as should be the case but is not by default, you have Option Strict On. The SelectedItem, SelectedValue and Item properties all return an Object reference so, if you want to use the value as a Keys value then you must cast it as type Keys. You can't assign an Object reference to a Keys variable with Option Strict On, which it should always be.
 
I don't really see that that's an issue. If there are two values in the enumeration that have the same numeric value then just let the user select either of them and they will then get what they expect.

That would be pretty ugly, considering there are 194 members in the enum...
 
That would be pretty ugly, considering there are 194 members in the enum...

I would suggest using the same list as is used for the ShortcutKeys property of a ToolStripMenuItem in the WinForms designer. That list includes 94 items. It might even be possible to determine what class provides the editor for that property and see exactly how it creates that list and do the same thing.
 
I would suggest using the same list as is used for the ShortcutKeys property of a ToolStripMenuItem in the WinForms designer. That list includes 94 items. It might even be possible to determine what class provides the editor for that property and see exactly how it creates that list and do the same thing.
ShortcutKeysEditor class, from its shared constructor
ShortcutKeysUI.validKeys = New Keys() { Keys.A, Keys.B, Keys.C, Keys.D, Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7, Keys.D8, Keys.D9, Keys.Delete, Keys.Down, Keys.E, Keys.End, Keys.F, Keys.F1, Keys.F10, Keys.F11, Keys.F12, Keys.F13, Keys.F14, Keys.F15, Keys.F16, Keys.F17, Keys.F18, Keys.F19, Keys.F2, Keys.F20, Keys.F21, Keys.F22, Keys.F23, Keys.F24, Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8, Keys.F9, Keys.G, Keys.H, Keys.I, Keys.Insert, Keys.J, Keys.K, Keys.L, Keys.Left, Keys.M, Keys.N, Keys.NumLock, Keys.NumPad0, Keys.NumPad1, Keys.NumPad2, Keys.NumPad3, Keys.NumPad4, Keys.NumPad5, Keys.NumPad6, Keys.NumPad7, Keys.NumPad8, Keys.NumPad9, Keys.O, Keys.OemBackslash, Keys.OemClear, Keys.OemCloseBrackets, Keys.Oemcomma, Keys.OemMinus, Keys.OemOpenBrackets, Keys.OemPeriod, Keys.OemPipe, Keys.Oemplus, Keys.OemQuestion, Keys.OemQuotes, Keys.OemSemicolon, Keys.Oemtilde, Keys.P, Keys.Pause, Keys.Q, Keys.R, Keys.Right, Keys.S, Keys.Space, Keys.T, Keys.Tab, Keys.U, Keys.Up, Keys.V, Keys.W, Keys.X, Keys.Y, Keys.Z }

Yes, it's 94 keys, did you count them before? :)
 
Back
Top