Hey guys. I'm working in WinForms and trying to create a ComboBox control that hosts a ListView when it's dropped down. I'm using ToolStripDropDown and ToolStripControlHost to accomplish this.
My problem is that i cannot display selected ListView item in the ComboBox when i set its DropDownStyle to DropDownList. Obviously this behavior only works when the actual ComboBox contains items in its collection. I ended up manually adding items to the ComboBox in my OnDoubleClick event and settings its selected index to 0 to display the item. But this still doesn't work. I'm out of ideas.
This is my ListViewComboBox class
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
[ToolboxItem(true)]
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class ListViewComboBox : ComboBox
{
private ToolStripControlHost _controlHost;
private ToolStripDropDown _dropDown;
public ListViewComboBox()
{
ListView innerListView = new ListView();
innerListView.BorderStyle = BorderStyle.None;
innerListView.View = View.SmallIcon;
innerListView.MultiSelect = false;
innerListView.HoverSelection = true;
innerListView.DoubleClick += new System.EventHandler(listView_DoubleClick);
_controlHost = new ToolStripControlHost(innerListView);
_controlHost.AutoSize = false;
_dropDown = new ToolStripDropDown();
_dropDown.Items.Add(_controlHost);
}
public void AutoSizeItems()
{
foreach (ListViewItem item in Items)
{
Size size = TextRenderer.MeasureText(item.Text, item.Font);
ListView lstView = (ListView)_controlHost.Control;
if (size.Width >= this.DropDownWidth)
{
this.DropDownWidth = size.Width + 40;
}
}
}
void listView_DoubleClick(object sender, System.EventArgs e)
{
if (sender is ListView)
{
ListView control = (ListView)sender;
base.Items.Clear();
if (control.SelectedItems.Count > 0)
{
base.Items.Add(control.SelectedItems[0].Text);
base.Text = control.SelectedItems[0].Text;
this.SelectedIndex = 0;
this.Focus();
}
_controlHost.PerformClick();
}
}
public new ListView.ListViewItemCollection Items
{
get
{
return ((ListView)_controlHost.Control).Items;
}
}
public ListViewGroupCollection Groups
{
get
{
return ((ListView)_controlHost.Control).Groups;
}
}
public new ListViewItem SelectedItem
{
get
{
return ((ListView)_controlHost.Control).SelectedItems[0];
}
}
private void ShowDropDown()
{
if (_dropDown != null)
{
_controlHost.Width = this.DropDownWidth;
_controlHost.Height = this.DropDownHeight;
_dropDown.Show(this, 0, this.Height);
_controlHost.Focus();
}
}
private const int WM_USER = 0x0400,
WM_REFLECT = WM_USER + 0x1C00,
WM_COMMAND = 0x0111,
CBN_DROPDOWN = 7,
LVM_FIRST = 0x1000,
LVM_SETCOLUMNWIDTH = (LVM_FIRST + 30);
public static int HIWORD(int n)
{
return (n >> 16) & 0xffff;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (WM_REFLECT + WM_COMMAND))
{
if (HIWORD((int)m.WParam) == CBN_DROPDOWN)
{
ShowDropDown();
return;
}
}
base.WndProc(ref m);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_dropDown != null)
{
_dropDown.Dispose();
_dropDown = null;
}
}
base.Dispose(disposing);
}
}
}
This is how i'm using the above control:
public Form1()
{
InitializeComponent();
ListViewItem item = new ListViewItem();
item.Font = new Font(item.Font.FontFamily.Name, 9, FontStyle.Bold);
item.ForeColor = Color.MediumBlue;
item.Text = "Test Entry";
listViewComboBox1.Items.Add(item);
listViewComboBox1.AutoSizeItems();
}