Wednesday, May 03, 2006

The dreaded SHIFT+SPACE of Datagrids and how to fix it

Anyone familiar with the .NET Datagrid class has probably run across the so-called "feature" where using SHIFT+SPACE selects the entire row. This is especially annoying when typing something like "How do I fix this?" in a text column. The row gets selected and if you manage to keep tying past the "I", you erase everything prior and all you get is "fix this?" Which is something I've been hearing for months from my users.

Today I decided to search once again on the web for a solution and found one on a fellow programmer's blog. He calls it a "dodge", but I think it's an excellent solution.

The Solution

Basically, you're overriding the Datagrid class, and then overriding the ProcessCmdKey method such that you can filter out the SHIFT+SPACE combo. However, I suppose it would be better to actually be able to alter the method that creates this behavior in the first place! Since we can't do that, this is the next best thing.

Just create the class below in your project, and then replace Datagrid objects with DataGridFix objects. You shouldn't need to make any other changes to your project.


using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace MyProject
{
///
/// This class is derived from the DataGrid class so that I can disable the "feature" that selects
/// a row by using SHIFT+SPACE
///

public class DataGridFix:System.Windows.Forms.DataGrid
{
// a couple of setup bits
const int WM_KEYDOWN = 256;
[DllImport("user32.dll")]
public static extern int GetKeyboardState(ref Byte pbKeyState);
[DllImport("user32.dll")]
public static extern int SetKeyboardState(ref Byte bpKeyState);

// over-ride the 'ProcessCmdKey' method
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Keys keyCode = ((Keys)msg.WParam.ToInt32()) & Keys.KeyCode;
if (msg.Msg == WM_KEYDOWN && keyCode == Keys.Space)
{
if (Control.ModifierKeys == Keys.Shift)
{
// if the keystate is SHIFT+SPACE, make it just a SPACE
byte[] keystates = new byte[255];
GetKeyboardState(ref keystates[0]);
keystates[16] = 0;
SetKeyboardState(ref keystates[0]);
SendKeys.Send(" ");
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData); // let the base method handle everything else as-is
}
}
}


I also need to give credit for the CSS code which make the code above easy to read.

CSS article

No comments: