Select to view content in your preferred language

C# IComPropertyPage escape/enter key handling

1761
7
06-23-2010 12:43 PM
LoganPugh
Frequent Contributor
I'm using ArcGIS 9.3.1 SP1.

I have a class that implements UserControl and IComPropertyPage in C# .NET. The UserControl contains several controls including a DataGridView. One of the DataGridView columns is an editable text column. When editing the text in a textbox, the normal behavior is that Escape cancels the edit, and Enter commits it.

However it appears that the ESRI Property Sheet code takes priority and whenever Escape or Enter are pressed, the window closes regardless of whether I am editing the text or not. I have tried setting keydown/previewkeydown event handlers, overriding WndProc and looking for key messages there, etc., but they never fire, in every case the property sheet closes before any of my code has a chance to run.

Has anyone else run into this issue and come up with any solution or workaround?

Thanks in advance.
0 Kudos
7 Replies
KirkKuykendall
Deactivated User
On 9.3.1 I can open Layer>Properties... then on the General tab I can type and hit the enter key and the escape key without the dialog closing.

If you write a custom class that inherits datagridview and override ProcessCmdKey, does it get called for enter/escape?
0 Kudos
LoganPugh
Frequent Contributor
I tried that once before and just tried it again, strangely, it never gets fired for any key, though OnKeyDown does for everything but Esc/Enter.
0 Kudos
LoganPugh
Frequent Contributor
It seems even PreProcessMessage, which is about as low level as you can go, never fires at all regardless of which control or UserControl I override it on. The only WinAPI level function that works is WndProc, and I think I may have stumbled upon the reason for it: WM_GETDLGCODE is the message that is sent before WM_KEYDOWN, and my guess is ESRI uses it to pre-filter all key input to their dialogs, which would explain why I can't trap Enter/Escape and preprocess other key messages.

I don't know enough about WinAPI to work around this though, or if this is what's really going on. Any ideas?
0 Kudos
LoganPugh
Frequent Contributor
Well I stumbled my way through to a solution. I was on the right track, you do need to override WndProc in whatever control you want to handle Escape/Enter keys and do something like this:

protected override void WndProc(ref System.Windows.Forms.Message message)
{
    const int WM_GETDLGCODE = 0x87;
    const int VK_ENTER = 0xd;
    const int VK_ESCAPE = 0x1b;
    const int DLGC_WANTALLKEYS = 0x0004;

    switch (message.Msg)
    {
        case WM_GETDLGCODE:
            switch ((int)message.WParam)
            {
                case VK_ENTER:
                case VK_ESCAPE:
                    message.Result = (IntPtr)DLGC_WANTALLKEYS;
                    base.ProcessKeyMessage(ref message);
                    break;
                default:
                    base.WndProc(ref message);
                    break;
            }
            break;
        default:
            base.WndProc(ref message);
            break;
    }
}


In this case of my DataGridView, I had to inherit from DataGridViewTextBoxColumn, DataGridViewTextBoxCell and DataGridViewTextBoxEditingControl to get to override the TextBox editing control's WndProc method, and then in the designer, set the DataGridView's column type to the custom column type.

// Customized TextBox Column
public class DataGridViewCustomTextBoxColumn : DataGridViewTextBoxColumn
{
    public DataGridViewCustomTextBoxColumn()
    {
        this.CellTemplate = new DataGridViewCustomTextBoxCell();
    }
}

// Customized TextBox Cell
public class DataGridViewCustomTextBoxCell : DataGridViewTextBoxCell
{
    public override Type EditType
    {
        get
        {
            return typeof(DataGridViewCustomTextBoxEditingControl);
        }
    }
}

// Customized TextBox Editing Control
public class DataGridViewCustomTextBoxEditingControl : DataGridViewTextBoxEditingControl
{
    protected override void WndProc(ref System.Windows.Forms.Message message)
    {
        const int WM_GETDLGCODE = 0x87;
        const int VK_ENTER = 0xd;
        const int VK_ESCAPE = 0x1b;
        const int DLGC_WANTALLKEYS = 0x0004;

        switch (message.Msg)
        {
            case WM_GETDLGCODE:
                switch ((int)message.WParam)
                {
                    case VK_ENTER:
                    case VK_ESCAPE:
                        message.Result = (IntPtr)DLGC_WANTALLKEYS;
                        base.ProcessKeyMessage(ref message);
                        break;
                    default:
                        base.WndProc(ref message);
                        break;
                }
                break;
            default:
                base.WndProc(ref message);
                break;
        }
    }
}
0 Kudos
JamesCrandall
MVP Alum
I missed this thread somehow, but wanted to post a similar experience but different solution.  I see you have resolved the issue but maybe take a look at my post/thread for possible alternate solution...

http://forums.arcgis.com/threads/3659-Capture-Enter-Keystroke-from-MaskedTextbox-on-UserControl

I could not even get the Enter Key event to fire/trapped at all.  Turns out it was very simple problem: use the KeyUp event instead of the KeyPress/KeyDown, then check for the specific key (in my case, I needed the Enter Key but you could also identify the Esc key too).  There is a KeyUp Event for the DataGridView control, but you'd probably still need to get at the KeyUp for the DataGridViewTextBoxEditingControl.

Private Sub txtPIDSearch_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtPIDSearch.KeyUp
        Try
            If e.KeyValue = Keys.Enter Then
               'do something
            End If
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
 End Sub
0 Kudos
LoganPugh
Frequent Contributor
If only it were that simple!

On ESRI Property Pages, KeyDown and KeyUp never get fired for Enter and Escape. The window is gone before that. You have to get down to the WinAPI level to trap the WM_GETDLGCODE message, set its result to DLGC_WANTALLKEYS, and then send the message on to the appropriate handler (I used ProcessKeyMessage). If you don't set its result, the handler won't get it because Property Pages by default make the system handle dialog keys (Escape/Enter).

I think it's a little different with Toolbars, but I will definitely keep your solution in mind if I have to do something similar. Thanks!
0 Kudos
JamesCrandall
MVP Alum
If only it were that simple!

On ESRI Property Pages, KeyDown and KeyUp never get fired for Enter and Escape. The window is gone before that. You have to get down to the WinAPI level to trap the WM_GETDLGCODE message, set its result to DLGC_WANTALLKEYS, and then send the message on to the appropriate handler (I used ProcessKeyMessage). If you don't set its result, the handler won't get it because Property Pages by default make the system handle dialog keys (Escape/Enter).

I think it's a little different with Toolbars, but I will definitely keep your solution in mind if I have to do something similar. Thanks!


Exactly,

My Toolbar is actually a UserControl that contains Texboxt/ComboBox controls.  The KeyUp/Down events would not get fired for Enter/Escape BUT they do fire with the KeyUp Event.  That's all I was attempting to show. 🙂

I was having the same problems you were having, along with similar UserControl control and was merely thinking that you *might* get away with a simpler solution than having to deal with the messaging stuff.
0 Kudos