views:

33

answers:

0

I am implementing a custom control in WinForms. This control needs to respond to a mnemonic character, and the mnemonic needs to focus the next control in the tab order - like a Label control does.

The ProcessMnemonic method is clearly the one to override. However, looking at how the Label control does it, for reference, shows that it relies heavily on WinForms internals:

  • To check whether it's OK to respond to the mnemonic, the Label uses an internal CanProcessMnemonic method.
  • The method requests a UIPermission, and then uses a bunch of internal classes and calls to verify that focus may be changed.
  • Focus is changed with the use of an internal "ParentInternal" field.

I didn't expect that responding to a mnemonic could be so involved. It seems to work if I omit all those internal calls and just use the non-internal Parent, but it makes me wonder: surely that code is not there for nothing, so my naive implementation must be lacking something?

Here's the Label's real code, tweaked slightly by me for readability:

[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
protected internal override bool ProcessMnemonic(char charCode)
{
    if ((!UseMnemonic || !IsMnemonic(charCode, Text)) || !CanProcessMnemonic() /*internal*/)
        return false;

    if (ParentInternal != null) /* internal */
    {
        IntSecurity.ModifyFocus.Assert(); /* internal */
        try
        {
            if (ParentInternal.SelectNextControl(this, true, false, true, false) && !ParentInternal.ContainsFocus)
                ParentInternal.Focus();
        }
        finally
        {
            CodeAccessPermission.RevertAssert();
        }
    }
    return true;
}

Here's my "naive" rewrite of it:

protected override bool ProcessMnemonic(char charCode)
{
    if ((!UseMnemonic || !IsMnemonic(charCode, Text)) || !Enabled || !Visible)
        return false;

    if (Parent != null)
        if (Parent.SelectNextControl(this, true, false, true, false) && !Parent.ContainsFocus)
            Parent.Focus();

    return true;
}

One obvious difference is that CanProcessMnemonic recursively checks the parent, which my code doesn't because this method is, inexplicably, internal...