Fernando
Fernando

Reputation: 151

C# Custom ComboBox - DropDown Position

I'm creating a ComboBox control using ToolStripControlHost and ToolStripDropDown that can host any kind of control in the DropDown window. For example, the DropDown window might display a listview or treeview or even another usercontrol.

I'm posting a simplified code below where dropdown host a usercontrol with a listview and a button like this:

enter image description here

The problem occurs when the control is positioned at the bottom of the screen in such a way that the dropdown window will extrapolate the lower boundary of the screen. When this occurs, the dropdown ends up hiding the control.

In this case, I'd like to fix the _dropDown.Show method call to show dropdown window as follows:

enter image description here

To repeat the problem, just run the code below and drag the window to the bottom of the screen and open the dropdown.

using System;
using System.Windows.Forms;

public class CustomComboBox : UserControl
{
    ToolStripDropDown _dropDown;

    public CustomComboBox()
    {
        var textbox = new TextBox();
        textbox.Location = new System.Drawing.Point(0, 0);
        textbox.Size = new System.Drawing.Size(this.Width - 22, 20);
        textbox.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
        this.Controls.Add(textbox);

        var button = new Button();
        button.Location = new System.Drawing.Point(this.Width - 22, -1);
        button.Size = new System.Drawing.Size(22, 22);
        button.Text = "\u2BC6"; 
        button.Anchor = AnchorStyles.Right | AnchorStyles.Top;
        button.Click += new System.EventHandler(this.Button_Click);
        this.Controls.Add(button);

        var dropDownControl = new DropDownControlTest();

        var controlHost = new ToolStripControlHost(dropDownControl);

        _dropDown = new ToolStripDropDown();
        _dropDown.AutoSize = true;              
        _dropDown.Items.Add(controlHost); 
    }

    void Button_Click(object sender, EventArgs e)
    {
        _dropDown.Show(this, 0, this.Height);
    }
}

public class DropDownControlTest : UserControl
{
    public DropDownControlTest()
    {
        var listview = new ListView();
        listview.Location = new System.Drawing.Point(3, 1);
        listview.Size =  new System.Drawing.Size(400,300);
        listview.View = View.Details;
        listview.Columns.Add("Col 1",100);
        listview.Columns.Add("Col 2",100);
        this.Controls.Add(listview);

        var button = new Button();
        button.Location = new System.Drawing.Point(3, 305);
        button.Text = "More...";
        this.Controls.Add(button);
    }
}

public class Form1 : Form
{
    private static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public Form1 ()
    {
        CustomComboBox ccBox = new CustomComboBox();
        ccBox.Location =  new System.Drawing.Point(10, 10);
        ccBox.Height = 20;

        this.Text = "Test CustomComboBox";
        this.Controls.Add(ccBox);
    }
}

Upvotes: 4

Views: 5575

Answers (2)

TnTinMn
TnTinMn

Reputation: 11801

You can use the ToolStripDropDown.Show Method (Control, Point, ToolStripDropDownDirection) overload to control the drop direction. The code will need to perform bounds checking to decide whether to place the dropdown above or below the textbox.

The following is a simplistic method for doing the bounds checking and was only tested on a single screen configuration.

First, make textbox a class level variable.

private TextBox textbox;
public CustomComboBox()
    {
    //var textbox = new TextBox();
    textbox = new TextBox();

The display logic is as follows.

void Button_Click(object sender, EventArgs e)
    {
    Point textBoxScreenLocation = textbox.PointToScreen(textbox.Location);

    // try to position _dropDown below textbox
    Point pt = textBoxScreenLocation;
    pt.Offset(0, textbox.Height);

    // determine if it will fit on the screen below the textbox
    Size dropdownSize = _dropDown.GetPreferredSize(Size.Empty);
    Rectangle dropdownBounds = new Rectangle(pt, dropdownSize);

    if (dropdownBounds.Bottom <= Screen.GetWorkingArea(dropdownBounds).Bottom)
        {   // show below
            _dropDown.Show(pt, ToolStripDropDownDirection.BelowRight);
        }
    else
        {   // show above
            _dropDown.Show(textBoxScreenLocation, ToolStripDropDownDirection.AboveRight);
        }
    }
}

Upvotes: 4

Gaurang Dave
Gaurang Dave

Reputation: 4056

I can not comment that is why I am answering your question. You can use the reflection and then re-position you control. I have found a custom combobox control same as you developed. Please check this. At least, you will get some idea what you need to do.

Upvotes: 2

Related Questions