我正在尝试创建一个ContextMenu,其中菜单中的某些项目包含多个项目。您可以将其视为尝试组合ToolStrip和ContextMenuItem。 我尝试过使用ToolStripControlHost,但这会产生焦点问题。它基本上要求你单击ToolStrip中的所有内容两次..
ContextMenuStrip m = new ContextMenuStrip();
ToolStrip tStrip = new ToolStrip(new ToolStripDropDownButton(), new ToolStripButton());
ToolStripControlHost tsHost = new ToolStripControlHost(tStrip);
m.Items.Add(tsHost);
有关如何实现这一目标的任何想法?
答案 0 :(得分:1)
对于不像上下文菜单那样的自定义弹出窗口,ContextMenuStrip太有吸引力了。这是可取的,因为当用户点击菜单外部时它会自动弹出。它有局限性,它不是一个非常好的控制主机。点击问题是经典问题,CMS捕获鼠标以检测用户何时在窗口外点击。
这真的应该是一种形式。为了给它提供与CMS相同的行为,但需要一些工作。您必须检测窗口外的鼠标单击,以便您可以使窗口消失。像CMS一样捕获鼠标不起作用。一个技巧是使用IMessageFilter,它允许您在输入消息传递到具有焦点的窗口之前查看输入消息。这是一个实现此目的的示例表单:
public partial class MyContextMenu : Form, IMessageFilter {
public MyContextMenu() {
InitializeComponent();
Application.AddMessageFilter(this);
}
protected override void OnFormClosed(FormClosedEventArgs e) {
Application.RemoveMessageFilter(this);
base.OnFormClosed(e);
}
public void Show(Control ctl, Point pos) {
this.StartPosition = FormStartPosition.Manual;
this.Location = ctl.PointToScreen(pos);
while (!(ctl is Form)) ctl = ctl.Parent;
this.Show((Form)ctl);
}
public bool PreFilterMessage(ref Message m) {
// Detect mouse clicks outside of the form
if (m.Msg == 0x201 || m.Msg == 0x204 || m.Msg == 0x207 ||
m.Msg == 0xA1 || m.Msg == 0xA4 || m.Msg == 0xA7) {
Point pos = new Point(m.LParam.ToInt32());
Control ctl = Control.FromHandle(m.HWnd);
if (ctl != null) pos = ctl.PointToScreen(pos);
pos = this.PointToClient(pos);
if (pos.X < 0 || pos.Y < 0 || pos.X >= this.Width || pos.Y >= this.Height) {
this.Close();
}
}
return false;
}
}
正常使用设计器来设计表单。你想至少给它一个不同的FormBorderStyle。使用提供的Show()方法重载与将其用于CMS的方式相同。请注意,只有当您单击应用程序所拥有的窗口时,表单才会弹出,与CMS不同。功能,而不是错误。