MoSlo
MoSlo

Reputation: 2870

ToolStripDropDownButton - changing dropdown behavior with Esc key

I have a custom control with a ToolStripDropDownButton. The ToolStripDropDownButton has a number of toolstrip items (specifically, a custom toolstrip items which are checkboxes). A user can select which checkbox items they want and I handle the DropDownClosed event and then utilize those checked items.

The objective is for a user to cancel his selection by hitting the escape key. The problem is that the DropDownClosed event also fires when the Escape key is pressed. So when a user selects the options and wants to hit Escape to cancel the selection, the DropDownClosed event fires and I end up 'applying' those settings.

I've tried playing around with the following overrides on the control hosting the ToolStripDropDownButton:

protected override bool ProcessCmdKey
protected override bool ProcessKeyPreview
protected override void WndProc

without much success as the dropdown seems to hide before any of these events are processed. What is the best way to modify this behavior?

Upvotes: 0

Views: 1574

Answers (3)

MoSlo
MoSlo

Reputation: 2870

Ok, the reason why the overrides were not working on the ToolStripDropDownButton is because it was not the component that had focus. The items on the dropdown had focus when the dropdown is being shown and all available overrides (ProcessCmdKey, ProcessDialogKey etc) on the toolBoxButton items are being fired when the dropdown is being shown.

In the end, I've made two derived classes for the ToolStrip item itself (a checkbox in this case) and the accommodating ToolStripDropDownButton.

public class EscapingToolStripCheckBox : CustomControls.ToolStripCheckBox
{
    private EscapingToolStripDropDownButton _parent;

    public EscapingToolStripCheckBox(EscapingToolStripDropDownButton parent)
        : base()
    {
        _parent = parent;
    }

    protected override bool ProcessCmdKey(ref Message m, Keys keyData)
    {
        if (keyData == Keys.Enter)
        {
            _parent.HandleSelection(false);
            return true;
        }
        else if (keyData == Keys.Escape)
        {
            _parent.HandleSelection(true);
            return true;
        }
        // Dont need to execute HandleSelection under any other condition. 

        return base.ProcessCmdKey(ref m, keyData);
    }

}

...where HandleSelection takes a boolean for whether the selection is to be cancelled or not.

    public void HandleSelection(bool selectionCancelled)
    {
        _selectionCancelled = selectionCancelled;
        this.HideDropDown();
    }

From there, I can easily check a property (either on the control itself or as part of the event arguments) as to whether the DropDownClosed event is considered cancelled or not.

Upvotes: 0

LarsTech
LarsTech

Reputation: 81675

Try using this version of the ToolStripDropDown where it intercepts the Esc key from closing the drop down:

public class ToolStripDropDownEx : ToolStripDropDown {

  protected override bool ProcessDialogKey(Keys keyData) {
    if (keyData == Keys.Escape)
      return true;
    else
      return base.ProcessDialogKey(keyData);
  }
}

Upvotes: 2

Veldmuis
Veldmuis

Reputation: 4868

What about the KeyDown or KeyPressed events? At least one of them should hopefully fire before the DropDownClosed event and then you can check whether Escape was pressed so you can set a flag for the DropDownClosed handler.

Edit: If ProcessCmdKey or ProcessKeyPreview is triggered after the DropDownClosed event you can build in a delay with a timer. The DropDownClosed starts the timer and then ProcessCmdKey or ProcessKeyPreview can set a flag if Escape is pressed. When the timer Ticks you can either undo or apply the checks done by the user.

Upvotes: 0

Related Questions