by Michael S. Kaplan, published on 2007/06/16 03:01 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2007/06/16/3330810.aspx
(HR would probably recommend against any more clever of a title for this blog post than the one with which it is currently saddled)
I have mentioned previously that I hate the Keys enumeration in the .NET Framework. And I even have explained a bit about why.
One reason I don't like it is that it encourages code to be written than confuses VIRTUAL KEY values on keys with the character assignments on those keys.
Even though they are sometimes not the same.
Just the other Dave ran into a problem caused by someone else hitting just such a misunderstanding. Someone working for Microsoft who wrote the code which has subsequently shipped in a version of the framework or two (maybe three or four!). His question went as follows:
I am investigating a problem where the text box created by a DataGridView when editing a field is dropping the period character when using the handwriting tip on an XPSP2 Tablet PC. For example, writing 4.1 in the tip is entered as 41 in the DataGridView’s text box. Running Spy++ on the process that owns the DataGridView, I can see that the control is receiving the correct sequence of WM_CHAR messages as if I typed 4.1 on the keyboard. Entering the same value in Notepad or other application that uses an edit control does not exhibit this problem. Additionally, I am unable to reproduce the problem with a text box that is on the same form as the DataGridView.
I am in the process of installing VS on the Tablet PC to try to determine where the WM_CHAR for the period character is being handled. In the meantime, I am curious if this is a known issue with the DataGridView.
Thanks,
Dave
The problem turns out to be that when one types that particular character whose Unicode code point is U+002e, that it shares an identity with a constant from winuser.h:
#define VK_DELETE 0x2E
And of course the code in DataGridView.ProcessKeyPreview is returning true and thus not processing several different values, including in this case Keys.Delete. And we skip right over that character, thinking it is one of those VK values that needs special handling rather than a character (all lost through a cast to that enumeration from a WPARAM of a window message where no one checked whether it was the right message to make that assumption with).
And if you take a value like 4.1 and skip over that FULL STOP then you are left with 41. And the bitter knowledge that someone forgot to do more homework on the meaning and [mis]usage of the Keys enumeration....
Now I don't just want to pick on the WinForms folks here.
I mean, sure, they screwed this one up.
And sure, they screw it up over and over when they try to use it.
But the original Windows side of this is just as bad with the set of VK_* values that are the same as the letters side by side with the ones that are not that got people started down this road, as I have pointed out previously (at the bottom of the post).
Pound for pound, introducing a long standing design flaw is worse than either extending it or making people more susceptible to it. :-)
This post brought to you by . (U+002e, a.k.a. FULL STOP)
Andy Kackle on 11 Mar 2009 11:00 AM:
So how do you get the period to show up in the DataGridView?
Christopher Poe AKA Triforce on 21 Feb 2011 4:50 PM:
Here is my solution to this, in a derived DataGridView:
<SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
Protected Overrides Function ProcessKeyPreview(ByRef m As System.Windows.Forms.Message) As Boolean
' This is a workaround for a bug in the base DataGridView key processing.
' See MSDN Blog: blogs.msdn.com/.../3330810.aspx
Const WM_CHAR As Integer = &H102
Dim pKey As Keys
Dim pProcessed As Boolean
' Map character to key - same way as done in base method, note that both the period and delete keys both map to Keys.Delete!
pKey = DirectCast(CInt(m.WParam), Keys) Or ModifierKeys
If (m.Msg = WM_CHAR) AndAlso (pKey = Keys.Delete) Then
' If it's a keypress message (WM_CHAR) and it gets mapped to the delete key, do not process it.
' The actual delete key should never generate a keypress anyhow, so this is a good workaround.
pProcessed = False
Else
' Process normally
pProcessed = MyBase.ProcessKeyPreview(m)
End If
Return pProcessed
End Function