2

Within our application, there is a usercontrol, which allows to enter a number (inside a numericupdown) followed by a combobox which allows to select the SI-Prefix ([p, n, µ, m, -, k, M, G, T] small to big)

Now, for easier usage, I thought it would be nice to capture the KeyPress-Event on the numericUpDown and set the combobox accordingly. (If m is pressed, select mili (m), if G is pressed, select Giga (G))

This works flawless with the following handler / selector:

 private void numericUpDown1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (char.IsLetter(e.KeyChar))
        {
            //Check, if its valid for si prefixes. 
            if (this.siSelector1.TrySelect(e.KeyChar)
            {
                e.Handled = true;
            }
        }
    }

Where TrySelect does nothing but the following:

public Boolean TrySelect(Char chr)
    {
        var entry = this.comboBox_siPrefix.Items.Cast<KeyValuePair<String,Double>>().Where(e => e.Key.Contains("(" + chr + ")")).FirstOrDefault();

        if (!entry.Equals(new KeyValuePair<String, Double>()))
        {
            this.comboBox_siPrefix.SelectedItem = entry;
            return true;
        }
        return false;
    }

That's fine, but everytime the user hears a "BING" whenever a non-numeric Key is pressed on the numericupdown.

I read about e.SuppressKeyPress, which unfortunately isn't available with KeyPressEventArgs - it's only available for KeyEventArgs.

So, trying the whole thing with the KeyDown-Event works. (No "BING") - but I wasn't able to capture capital keys, as every KeyDown will fire the Event immediately...

 private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
    {
        KeysConverter kc = new KeysConverter();
        if (char.IsLetter(kc.ConvertToString(e.KeyCode)[0]))
        {
            //Check, if its valid for si prefixes. 
            if (this.siSelector1.TrySelect(kc.ConvertToString(e.KeyCode)[0]))
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
            }
        }
    }

Any Ideas?

dognose
  • 20,360
  • 9
  • 61
  • 107
  • Wouldn't this be a duplicate: [Stop the 'Ding' when pressing Enter](https://stackoverflow.com/q/6290967/719186) – LarsTech Apr 11 '18 at 17:14
  • @LarsTech No, as `Keys.Enter` is a single key, which works with `KeyDown`-Event as the example shows. `SHIFT+G` is captured through `KeyPress`-Event, which lacks the `e.SuppressKeyPress`-Property. – dognose Apr 11 '18 at 17:17
  • I don't get the problem. If the user presses a key that you are not happy with it then it goes Ding. If you never want to hear the dingaling then always set e.Handled = true for non-numeric characters. SuppressKeyPress is irrelevant, the KeyPress event was already raised. KeyDown is not a good idea on a foreign keyboard layout. – Hans Passant Apr 11 '18 at 17:56
  • @HansPassant Yes, but in this case - on the `numericupdown` i'm happy with valid letters such as `m, k, G,T...` cause they should be send to another control for convinience - So I don't want a "Bing". `Handled=true` (Google it!) Does not remove the BING for `numericupdown` fields. (Bug or feature?) Only `e.SuppressKeyPress` does. – dognose Apr 11 '18 at 18:12

1 Answers1

2

Figured out a way:

When Using KeyDown-Event, you can use e.Modifiers to check, if another key is down'd at the same time.

I dunno why, but for the KeyDown-Event e.KeyValue as well as e.KeyCode always return the CAPITAL version of the key.

So, I modified the handler to convert every char to lower-case, and only convert it to upper-Case if SHIFT is pressed at the same time:

Works - no "BING" (for valid SI-Prefixes). :-)

private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
    {
        KeysConverter kc = new KeysConverter();
        char c = char.ToLower(kc.ConvertToString(e.KeyValue)[0]); 
        if (char.IsLetter(c))
        {
            //Caps? 
            if (e.Modifiers == Keys.Shift)
            {
                c = char.ToUpper(c);
            }

            //Check, if its valid for si prefixes.
            if (this.siSelector1.TrySelect(c))
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
            }
        }
    }

The above solution does not apply for µ (CTRL+ALT+m or ALT GR+m)


Update: This is not 100%, but I didn't get it by now:

  • IF the ALT-Key is pressed, The Char-Code always reports a "M".

Update 2:


So, I had to exclude the "m" from beeing matched with char.isLetter() (if alt is pressed) and finally add another check.

I found, that comparing e.KeyValue==77 worked as expected, while comparing c=='m' didn't... (then µ was inserted into the numericupdown, which it shouldn't)

if (ctrl && alt && c=='m'):

enter image description here

if (ctrl && alt && e.KeyValue==77)

enter image description here

Dunno why - Ideas?

private void numericUpDown1_KeyDown(object sender, KeyEventArgs e)
    {
        KeysConverter kc = new KeysConverter();
        char c = char.ToLower(kc.ConvertToString(e.KeyValue)[0]);

        Boolean ctrl = e.Control;
        Boolean alt = e.Alt;
        Boolean shift = e.Shift;
        int keyPadStart = (int)Keys.NumPad0;
        int keyPadEnd = (int)Keys.NumPad9;

        if (e.KeyValue >= keyPadStart && e.KeyValue <= keyPadEnd)
        {
            //send to numeric updown. 
            return;
        }

        if (char.IsLetter(c) && !alt)
        {
            if (shift) c = char.ToUpper(c);

            //Check, if its valid for si prefixes.
            if (this.siSelector1.TrySelect(c))
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
            }
        }

        //not working: if (ctrl && alt && c=='m')
        if (ctrl && alt && e.KeyValue==77)
        {
            //Check, if its valid for si prefixes.
            if (this.siSelector1.TrySelect('µ'))
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
            }

        }
    }
dognose
  • 20,360
  • 9
  • 61
  • 107