0

I have a form that contains a TableLayoutPanel with various controls and labels in it. One of them is a custom control that inherits from ComboBox that has extra auto-complete behavior (auto-completes on any text rather than just left to right). I didn't write the code for this control, so I'm not super familiar with how it works, but essentially upon clicking on the Combobox, it adds a ListBox below the ComboBox, within the same Panel of the TableLayoutPanel, that covers the normal drop down.

Unfortunately, the TableLayoutPanel prevents the ListBox from being fully visible when added, and only one item is shown. The goal is to get it to look like a normal ComboBox which would drop down to cover any controls below it.

Is there any way to allow a control that is in a TableLayoutPanel to overlap the TableLayoutPanel to get this to work as I want? I want to avoid any controls moving around due to the TableLayoutPanel growing to accommodate the ListBox.

Relevant code from the control:

void InitListControl()
        {
            if (listBoxChild == null)
            {
                // Find parent - or keep going up until you find the parent form
                ComboParentForm = this.Parent;

                if (ComboParentForm != null)
                {
                    // Setup a messaage filter so we can listen to the keyboard
                    if (!MsgFilterActive)
                    {
                        Application.AddMessageFilter(this);
                        MsgFilterActive = true;
                    }

                    listBoxChild = listBoxChild = new ListBox();
                    listBoxChild.Visible = false;
                    listBoxChild.Click += listBox1_Click;
                    ComboParentForm.Controls.Add(listBoxChild);
                    ComboParentForm.Controls.SetChildIndex(listBoxChild, 0); // Put it at the front
                }
            }
        }


        void ComboListMatcher_TextChanged(object sender, EventArgs e)
        {
            if (IgnoreTextChange > 0)
            {
                IgnoreTextChange = 0;
                return;
            }

            InitListControl();

            if (listBoxChild == null)
                return;

            string SearchText = this.Text;

            listBoxChild.Items.Clear();

            // Don't show the list when nothing has been typed
            if (!string.IsNullOrEmpty(SearchText))
            {
                foreach (string Item in this.Items)
                {
                    if (Item != null && Item.ToLower().Contains(SearchText.ToLower()))
                    {
                        listBoxChild.Items.Add(Item);
                        listBoxChild.SelectedIndex = 0;
                    }
                }
            }

            if (listBoxChild.Items.Count > 0)
            {
                Point PutItHere = new Point(this.Left, this.Bottom);
                Control TheControlToMove = this;

                PutItHere = this.Parent.PointToScreen(PutItHere);

                TheControlToMove = listBoxChild;
                PutItHere = ComboParentForm.PointToClient(PutItHere);

                TheControlToMove.Anchor = ((System.Windows.Forms.AnchorStyles)
                    ((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
                TheControlToMove.BringToFront();
                TheControlToMove.Show();
                TheControlToMove.Left = PutItHere.X;
                TheControlToMove.Top = PutItHere.Y;
                TheControlToMove.Width = this.Width;

                int TotalItemHeight = listBoxChild.ItemHeight * (listBoxChild.Items.Count + 1);
                TheControlToMove.Height = Math.Min(ComboParentForm.ClientSize.Height - TheControlToMove.Top, TotalItemHeight);
            }
            else
                HideTheList();
        }

Images:

Desired behavior

Current behavior

  • No child can overlap its container. You may want to have a [look at this post](http://stackoverflow.com/questions/39637490/winforms-splitterpanel-z-index-of-child-overlap-split/39649087#39649087). Or use a combobox; dropdowns are not really child controls but are displayed overlaid so they can even overlap the form border.. – TaW Sep 23 '16 at 07:34
  • I can't use a ComboBox because it doesn't have the extra auto-complete feature that I need. Interesting what you say about child controls not being able to overlap their container. Makes sense but I didn't know that was the case in all instances. If a dropdown can overlap a container, then shouldn't there be some way to mimic that behavior in a custom control? – user2961731 Sep 23 '16 at 18:06
  • Think of Dropdowns as temporary windows/forms! Yes, that is also an option.. Maybe you can code an auto-complete version of combox if you can't find aready-made one. – TaW Sep 23 '16 at 18:13
  • Was trying to avoid that, but maybe there's no way around it at this point. The ListBox overlay thing was working great until I needed to add the TablelayoutPanel to make the form auto-sizeable. Thanks for your comments on this. – user2961731 Sep 23 '16 at 18:26
  • Did you look at the link above? – TaW Sep 23 '16 at 18:29
  • I appreciate that link. I'll look into that approach as well. – user2961731 Sep 23 '16 at 21:48

1 Answers1

0

Going on the suggestion from TaW, I came up with a tentative solution. This form isn't re-sizable but does auto-size so that it looks ok if the user changes their DPI in Windows.

To resolve this, I moved the control out of the TableLayoutPanel to an arbitrary position in the Parent of the TableLayoutPanel. On form loading, I summed the coordinates of the TableLayoutPanel and an empty panel in the cell that I wanted the control to be located on top of. This worked for my needs but it feels like a kludge.

The better solution is probably to use Control.PointToScreen and Control.PointToClient methods, however I wasn't able to get these methods to give me the correct coordinates.