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 不同。功能,而不是错误。