Search code examples
c#winformstoolstripmenu

C# WinForms ToolStripTextBox sizing and detect key press


I have a very simple C# WinForm sample:

private System.Windows.Forms.ContextMenuStrip ct1;

var header = new ToolStripMenuItem("Header with long test like Lorem Ipsum");
header.Enabled = false;

var txt = new ToolStripTextBox();
txt.Text = "changeme";

ct1.Items.Clear();
ct1.Items.Add(header);
ct1.Items.Add(txt);

ct1.Show(x,y);

Now I have two issues with this:

  1. How can I ask the textbox to fill the full width of the menu (i.e. be as large as the largest item)? enter image description here

  2. If I press the Alt key, the menu closes. I can prevent it by handling the Closing event:

Like this:

private void ct1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
    e.Cancel = (e.CloseReason == ToolStripDropDownCloseReason.Keyboard);
}

However I want to be able to close by pressing Escape, and I also want to be able to use Alt key as input.

But now Alt and Escape are all or nothing. How can I differentiate between them?

Tried even on KeyDown event for the TextBox and also for ct1, but Alt key is not forwarded to there.


Solution

  • For your first question,

    While it may require some tweaking, this will allow you to set the width of the text box to a good degree:

    First, give your textbox a name and attach to these event handlers. This is required because the width of the context menu is not determined until it is shown.

    txt.Name = "changeNameTextBox";
    ct1.Opening += ct1_Opening;
    ct1.Closed += ct1_Closed;
    

    Then implement those event handlers:

    void ct1_Opening(object sender, EventArgs e)
    {
        ToolStripTextBox txt = ct1.Items.Find("changeNameTextBox", false)[0] as ToolStripTextBox;
        txt.Size = new Size(ct1.Width - 50, txt.Height);
    }
    
    void ct1_Closed(object sender, ToolStripDropDownClosedEventArgs e)
    {
        ToolStripTextBox txt = ct1.Items.Find("changeNameTextBox", false)[0] as ToolStripTextBox;
        txt.Size = new Size(0, 25);
    }
    

    As for your second question, you almost made it.

    Have that onClosing event, and modify its body like this:

    void ct1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
    {
        e.Cancel =
            e.CloseReason == ToolStripDropDownCloseReason.Keyboard
            && 
            Control.ModifierKeys.HasFlag(Keys.Alt); 
    }
    

    Hope this helps.