我在Form应用程序中使用ContextMenuStrip作为下拉菜单。确实,当我单击按钮时,ContextMenuStrip会显示在其下方。一切都很好,但是我真的想在鼠标离开其区域后自动关闭ContextMenuStrip。好的,所以我尝试使用MouseLeave事件。再次一切正常,但是当我向ContextMenuStrip中的某些ToolStripItem添加下拉项时,mouseLeave事件不会将此新区域识别为ContextMenuStrip的一部分。这是我最新的尝试,但尚未完成。您知道如何解决此问题吗?
private void ContextMenuStrip_MouseLeave(object sender, EventArgs e)
{
ContextMenuStrip cms = (sender is ContextMenuStrip) ? sender as ContextMenuStrip : null;
if (cms != null)
{
//List<Rectangle> cmsFullArea = new List<Rectangle>();
//cmsFullArea.Add(new Rectangle(cms.Bounds.Location, cms.Bounds.Size));
bool itemIsPressed = false;
for (int i = 0; i < cms.Items.Count; i++)
{
if (cms.Items[i].Pressed) { itemIsPressed = true; break; }
}
if (!itemIsPressed) { cms.Close(); }
}
}
当我将CMS留给dropDown项目时,此方法工作正常,但当我也将其留给以后时,此方法不起作用。我离开他的任何区域时,都需要关闭整个CMS。
答案 0 :(得分:1)
添加一个区域变量,该变量将为ContextMenuStrip
加上DropDownMenus
。
private Region rgn = new Region();
初始化区域:
public Form1() {
InitializeComponent();
rgn.MakeEmpty();
}
ContextMenuStrip
打开更新区域时:
private void contextMenuStrip1_Opened( object sender, EventArgs e ) {
rgn.Union( contextMenuStrip1.Bounds );
}
在离开事件中,检查鼠标是否在该区域内:
private void contextMenuStrip1_MouseLeave( object sender, EventArgs e ) {
Point pnt = Cursor.Position;
if( rgn.IsVisible( pnt ) == false ) {
rgn.MakeEmpty();
contextMenuStrip1.Close();
}
}
创建新的ToolStripDropDownMenu
并将项目添加到toolStripMenuItem0
时,请添加以下事件处理程序:
//toolStripMenuItem0 is an item of your ContextMenuStrip
toolStripMenuItem0.DropDown.MouseLeave += DropDown_MouseLeave;
toolStripMenuItem0.DropDown.Opened += DropDown_Opened;
toolStripMenuItem0.DropDown.Closed += DropDown_Closed;
private void DropDown_Closed( object sender, ToolStripDropDownClosedEventArgs e ) {
ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)sender;
rgn.Exclude( tsddm.Bounds ); //remove rect from region
}
private void DropDown_Opened( object sender, EventArgs e ) {
ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)sender;
rgn.Union( tsddm.Bounds ); //add rect to region
}
private void DropDown_MouseLeave( object sender, EventArgs e ) {
Point pnt = Cursor.Position;
if( rgn.IsVisible( pnt ) == false ) {
rgn.MakeEmpty();
contextMenuStrip1.Close();
}
}
对每个 DropDownMenu you create
执行相同操作。
答案 1 :(得分:0)
正如我在评论中保证的那样,我想针对该问题发布另一种解决方案。
首先,有用于事件句柄的MouseLeave方法。此方法是ContextMenuStrip(CMS)和ToolStripDropDownMenu(TSDDM)通用的。
private void ContextMenuStrip_MouseLeave(object sender, EventArgs e)
{
ContextMenuStrip cms = (sender is ContextMenuStrip) ? sender as ContextMenuStrip : null;
//Recognize CMS or TSDDM, in this case we dont need anything else
if (cms != null)
{
//Check, if mouse position is on any of CMS DropDownMenus.
//If false, close CMS. If true, we dont want to close it - CMS is actively in use
if (!IsMouseOnDropDown(cms.Items)) { cms.Close(); }
}
else
{
ToolStripDropDownMenu ddm = (sender is ToolStripDropDownMenu) ? sender as ToolStripDropDownMenu : null;
if (ddm != null)
{
//As above, check mouse position against items DropDownMenus
if (IsMouseOnDropDown(ddm.Items)) { return; }
//Declare our CMS
cms = GetPrimaryOwner(ddm);
//Get TSDDM owner
//var is important here, because we dont know if it is CMS or another TSDDM!!!
//Also TSDDM and CMS have the same properties for our purpose, so var is OK
var owner = ddm.OwnerItem.Owner;
Point pnt = Cursor.Position;
//If owner doesn't contains mouse position, close whole CMS
if (!owner.Bounds.Contains(pnt))
{
cms.Close();
}
else
{
//If does, we need to check if mouse position is exactly on parent item,
//because its prevent to TSDDM unnecessary close/open
//(explanation: Mouse leave TSDDM -> TSDDM close;
//Mouse is on parent item -> TSDDM open)
for (int i = 0; i < owner.Items.Count; i++)
{
//Define own rectangle, because item has its own bounds against the owner
//so we need to add up their X and Y to get the real one
int x = owner.Bounds.X + (owner.Items[i] as ToolStripMenuItem).Bounds.X;
int y = owner.Bounds.Y + (owner.Items[i] as ToolStripMenuItem).Bounds.Y;
Rectangle rect = new Rectangle(new Point(x, y), (pupik.Items[i] as ToolStripMenuItem).Bounds.Size);
//If its our DropDownMenu and mouse position is in there,
//we dont want to close ddm
if ((owner.Items[i] as ToolStripMenuItem).DropDown == ddm
&& rect.Contains(pnt))
{
return;
}
}
ddm.Close();
}
}
}
}
上面您可以看到IsMouseOnDropDown和GetPrimaryOwner方法,因此有代码:
private static bool IsMouseOnDropDown(ToolStripItemCollection itemCollection)
{
Point pnt = Cursor.Position;
//All what we do is check, if some of DropDownMenus from input collection is active (Visible)
//and if mouse position is in it
for (int i = 0; i < itemCollection.Count; i++)
{
if ((itemCollection[i] as ToolStripMenuItem).DropDown.Visible
&& (itemCollection[i] as ToolStripMenuItem).DropDown.Bounds.Contains(pnt))
{
return true;
}
}
return false;
}
private static ContextMenuStrip GetPrimaryOwner(ToolStripDropDownMenu dropDownMenu)
{
//All what we do is take owner by owner until we find our CMS,
//which is the last one -> primary owner
object cmsItems = dropDownMenu;
while (!(cmsItems is ContextMenuStrip))
{
cmsItems = (cmsItems as ToolStripDropDownMenu).OwnerItem.Owner;
}
return cmsItems as ContextMenuStrip;
}
我们需要做的最后一件事是为每个DropDownMenu和ContextmenuStrip处理mouseLeave事件
this.ContextMenuStrip1.MouseLeave += new System.EventHandler(ContextMenuStrip_MouseLeave);
this.StripMenuItem1.DropDown.MouseLeave += new System.EventHandler(ContextMenuStrip_MouseLeave);
在此示例中,一切对我来说都很好,因此,如果发现错误,请告诉我。 这只是一个例子,所以我不在那里写Try / Catch。