我创建了自己的类似ComboBox的控件,其中下拉部分包含一棵树。我已经看到这些解决方案使用普通的ComboBox并覆盖WndProc,但是尽管有很多代码,但总有一些奇怪的行为。所以我决定让它变得简单:只是一个带有 ToolStripDropDown/ToolStripControlHost 的标签,当鼠标按下标签时会打开它。缺少的组合框三角形不会受到伤害。
一切都很完美,除了一件小事:就像股票 ComboBox 一样,我希望当我再次单击标签时隐藏下拉列表。但是当我单击它时,下拉列表会隐藏一瞬间,只是为了再次出现。如果我在标签外部单击,下拉菜单会隐藏,就像它应该的那样。
public class RepoNodeComboBox: Label
{
RepoTreeView repoTreeView;
ToolStripControlHost treeViewHost;
ToolStripDropDown dropDown;
bool isDropDownOpen;
public int DropDownHeight;
public RepoNodeComboBox()
{
repoTreeView = new RepoTreeView();
repoTreeView.BorderStyle = BorderStyle.None;
repoTreeView.LabelEdit = false;
treeViewHost = new ToolStripControlHost(repoTreeView);
treeViewHost.Margin = Padding.Empty;
treeViewHost.Padding = Padding.Empty;
treeViewHost.AutoSize = false;
dropDown = new ToolStripDropDown();
dropDown.CanOverflow = true;
dropDown.AutoClose = true;
dropDown.DropShadowEnabled = true;
dropDown.Items.Add(treeViewHost);
dropDown.Closing += dropDownClosing;
TextAlign = ContentAlignment.MiddleLeft;
BackColor = SystemColors.Window;
BorderStyle = BorderStyle.FixedSingle;
DropDownHeight = 400;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (dropDown != null)
{
dropDown.Dispose();
dropDown = null;
}
}
base.Dispose(disposing);
}
// when mouse goes down on the label, this is executed first
void dropDownClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
// just to test if I can get more out of it than with dropdown.Visible
isDropDownOpen = false;
}
// this is subsidiary to the Closing event of the dropdown
protected override void OnMouseDown(MouseEventArgs e)
{
if (dropDown != null)
{
if (isDropDownOpen)
{
dropDown.Hide();
}
else
{
repoTreeView.Size = new Size(Width, DropDownHeight);
treeViewHost.Width = Width;
treeViewHost.Height = DropDownHeight;
dropDown.Show(this, 0, Height);
isDropDownOpen = true;
}
}
base.OnMouseDown(e);
}
}
据我所知(断点(,下拉列表首先捕获 MOUSEDOWN 事件以关闭自身。只有在那之后,我的标签才会通过 MOUSEDOWN 事件传递,并且由于它看到下拉列表已关闭,因此它认为标签已被单击,就像第一次一样 - 并再次打开下拉列表。
因此,标签似乎没有机会知道鼠标下降是否是关闭下拉项的结果。我可以每隔一个事件打开它,但这不需要发生其他关闭事件。
有没有办法确保即使我单击标签,打开的下拉项也会关闭?
尝试在浮动主机关闭时检查鼠标位置:
void dropDownClosing(object sender, CancelEventArgs e) {
isDropDownOpen = this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition));
}
在 MouseDown 代码上,确保在 true 块中将 isDropDownOpen 设置为 false:
protected override void OnMouseDown(MouseEventArgs e) {
if (dropDown != null) {
if (isDropDownOpen) {
isDropDownOpen = false;
dropDown.Hide();
} else {
isDropDownOpen = true;
repoTreeView.Size = new Size(Width, DropDownHeight);
treeViewHost.Width = Width;
treeViewHost.Height = DropDownHeight;
dropDown.Show(this, 0, Height);
}
}
base.OnMouseDown(e);
}