我的问题是,当我将DropDownStyle设置为 DropDownList 时,我无法在ComboBox中显示所选的ListView项。显然,只有当实际的ComboBox在其集合中包含项时,此行为才有效。我最终手动将项目添加到我的OnDoubleClick事件中的ComboBox,并将其选定的索引设置为0以显示该项目。但这仍然行不通。我没有想法。
这是我的ListViewComboBox类
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);
}
}
}
这就是我使用上述控件的方式:
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();
}
答案 0 :(得分:0)
问题与将控件上的绘制模式设置为所有者绘制有关。如果有人感兴趣,这里是最终控件的样子。解决方案并非真正的最终实现,更多的是概念验证。它需要进行重大重构才能更好地模拟下拉控件的功能,并且通用性足以托管多个控件。但是我会把它留给以后。
[ToolboxItem(true)]
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class ListViewComboBox : ComboBox
{
#region Fields
/// <summary>
/// Used as the list view host.
/// </summary>
private readonly ToolStripControlHost _controlHost;
/// <summary>
/// Used as the pop-up window.
/// </summary>
private ToolStripDropDown _dropDown;
/// <summary>
/// Search input area.
/// </summary>
private ToolStripTextBox _searchBox;
/// <summary>
/// Contains tooltip instance used to show tooltip over list view item.
/// </summary>
private ToolTip _toolTip;
/// <summary>
/// Indicates whether the list view has been dropped down.
/// </summary>
private bool _dropped;
/// <summary>
/// Indicates whether the list view has been auto-sized.
/// </summary>
private bool _autoSized;
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of <see cref="ListViewComboBox"/>.
/// </summary>
public ListViewComboBox()
{
ListView innerListView = new ListView();
innerListView.Columns.Add("Vendors");
innerListView.HeaderStyle = ColumnHeaderStyle.None; // Hide column headers
innerListView.BorderStyle = BorderStyle.None;
innerListView.View = View.Details; // 1 item per line
innerListView.MultiSelect = false;
innerListView.FullRowSelect = true;
innerListView.HideSelection = false;
innerListView.ShowGroups = true;
innerListView.ShowItemToolTips = false;
innerListView.DoubleClick += new System.EventHandler(ListView_DoubleClick);
innerListView.ItemMouseHover += new ListViewItemMouseHoverEventHandler(ListView_ItemMouseHover);
// Default height for now
DropDownHeight = 300;
_controlHost = new ToolStripControlHost(innerListView);
_controlHost.AutoSize = false;
_toolTip = new ToolTip();
_searchBox = new ToolStripTextBox();
_searchBox.BorderStyle = BorderStyle.FixedSingle;
_searchBox.Dock = DockStyle.Fill;
_searchBox.Text = "Search";
_searchBox.Width = Width;
_searchBox.TextChanged += new EventHandler(SearchBox_TextChanged);
_searchBox.LostFocus += new EventHandler(SearchBox_LostFocus);
_searchBox.GotFocus += new EventHandler(SearchBox_GotFocus);
_dropDown = new ToolStripDropDown();
_dropDown.DropShadowEnabled = false;
_dropDown.Items.Add(_searchBox);
_dropDown.Items.Add(_controlHost);
}
#endregion
#region Event Handlers
/// <summary>
/// Selects the item clicked in the list view and updates
/// combo box to display the selected item's text value.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListView_DoubleClick(object sender, EventArgs e)
{
if (sender is ListView)
{
ListView control = (ListView)sender;
DataSource = null;
if (control.SelectedItems.Count > 0)
{
// Bind the first selected item to the combo box
// to display the item's textual value
IList<ListViewItem> source = new List<ListViewItem>(1);
source.Add(control.SelectedItems[0]);
DataSource = source;
DisplayMember = "Text";
Tag = control.SelectedItems[0].Tag;
SelectedIndex = 0;
}
HideDropDown();
}
}
/// <summary>
/// Applies tooltip on item hover.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListView_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs e)
{
if (!string.IsNullOrEmpty(e.Item.ToolTipText))
{
_toolTip.SetToolTip(InnerControl, e.Item.ToolTipText);
}
else
{
_toolTip.SetToolTip(InnerControl, e.Item.Text);
}
}
/// <summary>
/// Clears search box when focus is set.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SearchBox_GotFocus(object sender, EventArgs e)
{
_searchBox.Clear();
}
/// <summary>
/// Titles the search box when focus is lost.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SearchBox_LostFocus(object sender, EventArgs e)
{
_searchBox.Text = "Search";
}
/// <summary>
/// Performs search on search box text change.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SearchBox_TextChanged(object sender, EventArgs e)
{
ListViewItem item = InnerControl.FindItemWithText(_searchBox.Text);
if (item != null)
{
InnerControl.SelectedItems.Clear();
InnerControl.EnsureVisible(item.Index);
item.Selected = true;
item.Focused = true;
InnerControl.Select();
}
}
#endregion
#region Properties
/// <summary>
/// Provides access to the item collection.
/// </summary>
public new ListView.ListViewItemCollection Items
{
get
{
return InnerControl.Items;
}
}
/// <summary>
/// Provides access to the group collection.
/// </summary>
public ListViewGroupCollection Groups
{
get
{
return InnerControl.Groups;
}
}
/// <summary>
/// Gets selected item.
/// </summary>
public new ListViewItem SelectedItem
{
get
{
if (InnerControl.SelectedItems.Count > 0)
{
return InnerControl.SelectedItems[0];
}
return null;
}
}
/// <summary>
/// Gets selected item.
/// </summary>
public new object SelectedValue
{
get
{
return SelectedItem;
}
}
/// <summary>
/// Gets selected text.
/// </summary>
public new string SelectedText
{
get
{
if (SelectedItem != null)
{
return SelectedItem.Text;
}
return null;
}
}
protected ListView InnerControl
{
get
{
return _controlHost.Control as ListView;
}
}
#endregion
#region Public Members
/// <summary>
/// Auto-sizes the drop-down based on the content lengths.
/// </summary>
public void AutoSizeItems()
{
AutoSizeInternal(InnerControl, false);
}
/// <summary>
/// Sets an item in the list as selected.
/// </summary>
/// <param name="value">The item value to search for.</param>
public void SetValue(string value)
{
ListViewItem item = InnerControl.FindItemWithText(value);
if (item != null)
{
item.Selected = true;
IList<ListViewItem> source = new List<ListViewItem>(1);
source.Add(item);
DataSource = source;
DisplayMember = "Text";
Tag = item.Tag;
SelectedIndex = 0;
}
}
/// <summary>
/// Opens the drop-down.
/// </summary>
public void ShowDropDown()
{
if (_dropDown != null)
{
_controlHost.Width = DropDownWidth;
_controlHost.Height = DropDownHeight;
// Highlight selected item
if (!string.IsNullOrEmpty(Text))
{
ListViewItem foundItem = InnerControl.FindItemWithText(Text);
if (foundItem != null)
{
foundItem.Selected = true;
foundItem.EnsureVisible();
}
else
{
// Clear items which were clicked, but not selected
if (InnerControl.SelectedItems.Count > 0)
{
InnerControl.SelectedItems.Clear();
}
}
}
_dropDown.Show(this, 0, Height);
_controlHost.Focus();
_dropped = true;
}
}
/// <summary>
/// Collapses the drop-down.
/// </summary>
public void HideDropDown()
{
if (_dropDown != null)
{
_dropDown.Hide();
_dropped = false;
}
}
#endregion
#region Protected Members
/// <summary>
/// Process Win32 loop messages.
/// </summary>
/// <param name="m">The message to process.</param>
protected override void WndProc(ref Message m)
{
if (m.Msg == (NativeMethods.WM_REFLECT + NativeMethods.WM_COMMAND))
{
if (NativeMethods.HIWORD((int)m.WParam) == NativeMethods.CBN_DROPDOWN)
{
// Prevent ComboBox from dropping down its list
RecreateHandle();
NativeMethods.SendMessage(Handle, NativeMethods.CB_SHOWDROPDOWN, 0, 0);
// Autosize the list view
if (!_autoSized)
{
AutoSizeItems();
_autoSized = true;
}
// Show/Hide dropped down based on current state
if (!_dropped)
{
ShowDropDown();
}
else
{
HideDropDown();
}
return;
}
}
base.WndProc(ref m);
}
/// <summary>
/// Disposes the control and releases memory.
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_dropDown != null)
{
_dropDown.Dispose();
_dropDown = null;
}
}
if (_toolTip != null)
{
_toolTip.Dispose();
_toolTip = null;
}
base.Dispose(disposing);
}
#endregion
#region Helper Members
private void AutoSizeInternal(ListView lv, bool adjustForVerticalScrollBar)
{
int resizeByContent = 0;
int resizeByHeader = 0;
for (int i = 0; i < lv.Columns.Count; i++)
{
lv.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
resizeByContent = lv.Columns[i].Width;
lv.Columns[i].AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
resizeByHeader = lv.Columns[i].Width;
lv.Columns[i].Width = (resizeByHeader > resizeByContent) ? resizeByHeader : resizeByContent;
DropDownWidth = lv.Columns[i].Width + 20;
if (DropDownWidth < Width)
{
DropDownWidth = Width;
}
}
}
#endregion
}
#region Native Methods Helper
internal static class NativeMethods
{
#region Win32 API Stubs
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr handle, int message, int wparam, int lparam);
#endregion
#region Constants
internal const int WM_USER = 0x0400,
WM_REFLECT = WM_USER + 0x1C00,
WM_COMMAND = 0x0111,
WM_PAINT = 0xf,
CBN_DROPDOWN = 7,
CB_SHOWDROPDOWN = 0x14F;
#endregion
internal static int HIWORD(int n)
{
return (n >> 16) & 0xffff;
}
}
#endregion