0

I started with an MDI application, but window management was not user friendly, so I converted everything into a tabbed browsing model.

When I set a Form with TopLevel = false and make it the child of another Form, everything works correctly, except when you click on text in a TextBox, the cursor goes to the beginning of the TextBox instead of where you clicked. You cannot click on a specific insertion point, nor select a range of text. Keyboard input is unaffected. Here's some simple code to reproduce this:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        var form1 = new Form();
        var form2 = new Form();
        var tab = new TabControl();
        tab.TabPages.Add("first");
        tab.Dock = DockStyle.Fill;
        form2.TopLevel = false;
        form1.Controls.Add(tab);
        tab.TabPages[0].Controls.Add(form2);
        form2.Controls.Add(new TextBox { Top = 10, Left = 10, Text = "Blah blah blah" });
        form2.Controls.Add(new TextBox { Top = 35, Left = 10, Text = "more text here blah blah" });
        form2.Visible = true;
        Application.Run(form1);
    }
}

Just run this sample code, and click in the middle of the text in either text box.

I overrode WndProc, and it looks like the forms get the following messages in this order when clicking on a different box (number of > arrows to indicate nested calls):

> form2.WM_PARENTNOTIFY
> form1.WM_PARENTNOTIFY
> form2.WM_MOUSEACTIVATE
>> form1.WM_MOUSEACTIVATE
> form1.WM_WINDOWPOSCHANGING
> form1.WM_WINDOWPOSITIONCHANGED
> form1.WM_ACTIVATEAPP
> form1.WM_NCACTIVATE
> form1.WM_ACTIVATE

What else I tried: I did a bunch of work converting the child forms into UserControls with title bars, close buttons, drag resizing and moving, etc, but there were all kinds of problems with it, events not hooking up correctly because there was no FormClosing/FormClosed events, custom controls finding the wrong parent form, etc.

So making the children forms TopLevel = false instead of MdiChild does exactly what I need, except this one bug. All other controls get focus properly, interacting with keyboard and mouse as expected. This is a specific problem with the WinForms TextBox control.

Does anyone know how to fix the TextBox focus issue shown by the above sample application?

Bryce Wagner
  • 1,151
  • 7
  • 18

1 Answers1

0

I did a whole bunch of searching before hand, but it wasn't until a day after posting that I found Windows Forms: Unable to Click to Focus a MaskedTextBox in a Non TopLevel Form via the related questions feature. It turns out this question is mostly a duplicate of that one. Hans Passant's answer on that question gave me the correct direction.

Converting all the child forms into UserControls didn't work because stuff that was expecting to be hosted by a Form was finding the top level form instead of the child forms. But Hans's answer points out that if you set TopLevel = false and FormBorderStyle = None on a form, a Form will basically act like a normal control. And by doing it this way, all the stuff that expects a Form will actually get a Form.

So all the window management code I had written for UserControls turned out to be useful (drawing and handling draggable borders, titlebar, maximize and close buttons), and all I had to do was convert the UserControls back into Forms with TopLevel = false, and then set FormBorderStyle = None in the OnShown.

Bryce Wagner
  • 1,151
  • 7
  • 18