不要在选择特定项目时关闭ContextMenuStrip

16

是否可以在选择/勾选某些项目后保持ContextMenuStrip菜单打开状态?

我计划使用简单的ContextMenuStrip设置一个筛选器(这样我可以在菜单或右键单击选项中使用相同的筛选器)。

该菜单列出了许多项目,我希望用户能够使用基本的检查功能进行选择。一旦选择完成,用户就可以单击“激活筛选器”选项,或单击菜单外部以激活或取消筛选器。

在选择/单击事件上,菜单通常会关闭。 是否可以在单击事件上保持菜单打开?

9个回答

28

如果未来的程序员想知道如何做到这一点,这就是我发现的方法。这不会关闭上下文菜单,即使点击了任何项。创建上下文菜单关闭事件并设置一个if语句,以取消关闭事件,如果关闭原因是itemclicked。

private void contextMenuStrip_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
    if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
        e.Cancel = true;
}

1
如果我理解问题正确的话,这并没有完全回答它,因为他们只想让上下文菜单保持打开状态,以便某些项目。例如,上下文菜单项包括:选项A、选项B、选项C和接受;如果点击其中一个选项,则应该保持上下文菜单打开(该选项将被选中),但是如果点击接受,则应该关闭上下文菜单。 - jonvw
这并不能正确地解决问题。请参考此答案:https://dev59.com/cHNA5IYBdhLWcg3wrf83#38659888 获取完整的解决方案。 - Ryan_S

4

关闭事件

将e.Cancel设置为true以保持菜单打开状态

唯一的问题是该事件不会告诉您点击了什么,因此您需要自己跟踪。在要保持菜单打开的项目的单击事件中设置某种标志。然后在关闭事件中检查标志并适当地设置e.Cancel。


这种方法似乎比现有的解决方案更优雅。我在基于ContextMenu的Closing事件中将e.Cancel设置为true,根据建议在单击的各个项上设置标志。但是,由于Cancel事件仅在关闭事件期间设置,因此它会滞后一步。是否有一种方法可以在项目单击事件中为关闭事件设置Cancel标志? - barry

3

为了防止右键菜单在点击某个项目后关闭,请按照以下步骤操作。

在ContextMenuItems的mousedown事件中将标志设置为false,然后在contextmenu的closing事件中将其重新设置为true。

示例:

Private blnClose As Boolean = True

Private Sub MoveUpToolStripMenuItem_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MoveUpToolStripMenuItem.MouseDown

     blnClose = False

End Sub

Private Sub ContextMenuStrip1_Closing(ByVal sender As Object, ByVal e As System.Windows.Forms.ToolStripDropDownClosingEventArgs) Handles ContextMenuStrip1.Closing

     e.Cancel = Not blnClose
     blnClose = True

End Sub

6
你选择了一个不属于你编码语言的答案,并且建议使用全局变量?这里还有更多相关的答案。 - Lee Louviere
这并不能正确地解决问题。请参考此答案:stackoverflow.com/a/38659888 获取完整的解决方案。 - Ryan_S

2
我发现奇怪的是ContextMenuStrip.Closing事件在ToolStripMenuItem.Click事件之前触发。 解决方法是使用ContextMenuStrip.ItemClicked事件,在其中使用e.ClickedItem检查是否为其中一个项目,当单击该项目时,不会关闭ContextMenuStrip并设置相应的标志。 然后在ContextMenuStrip.Closing中,如果也设置了该标志,则可以设置e.Cancel = true;。 不要忘记重置标志。
bool isRunAtStartupClicked;
private void ContextMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{   
    if (e.ClickedItem == trayIcon.ContextMenuStrip.Items["miRunAtStartup"])
    {   
        isRunAtStartupClicked = true;
    }
}

private void ContextMenuStrip_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{   
    if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
    {   
        if (isRunAtStartupClicked)
        {   
            isRunAtStartupClicked = false;
            e.Cancel = true;
        }
    }
}

1
这是我的方法;它不会闪烁,并且我认为它更加灵活。
如果您有一组ToolStripMenuItems要用作切换按钮(选项开/关),请尝试以下操作:
ctxWildCards只是我的ContextMenuStrip,用于基于文件类型选择过滤器-用于搜索或FileDialogs)
这是使用Visual Basic编写的(显然!;),因此您可以通过编程方式或使用“Handles…”子句添加处理程序。
  Private Sub OnOffToolStripMenuItem_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) 

    Dim t = TryCast(sender, ToolStripMenuItem)
    If Not t Is Nothing Then
        'Since you may have more On/off-Items, check to see if the Owner is the ContextMenuStrip 
        If t.Owner Is ctxWildCards Then
           ' The ContextMenuStrip will stay open on Right-click, i.e. the user can check and close by clicking 'normally'
            ctxWildCards.AutoClose = (e.Button = Windows.Forms.MouseButtons.Left)
        End If
        'Just me using a custom image for checked items.
        t.Checked = Not t.Checked
        t.Image = If(t.Checked, rdoImage, Nothing)
    End If
  End Sub

 ' On leaving ToolStripMenuItems of the ContextMenuStrip, allow it to AutoClose
  Private Sub OnOffToolStripMenuItem_MouseLeave(sender As System.Object, e As System.EventArgs)
  ctxWildCards.AutoClose = True
End Sub

1
在 OnClosing 事件中,执行以下操作:e.Cancel = e.CloseReason != ToolStripDropDownCloseReason.CloseCalled;然后当您决定关闭时,调用 Close() 方法。

1

我认为在ContextMenuStrip中没有这个属性。

我们在应用程序中使用的解决方法是,在ContextMenuStrip的clicked事件上进行一些处理,然后如果我们希望上下文菜单保持打开状态,我们只需再次调用ContextMenuStrip.Show。

如果ContextMenuStrip只有一级菜单,那么这将很好地工作。如果有子菜单和子子菜单,则必须重新选择单击之前打开的菜单,我不确定如何完成这项任务...


谢谢!我已经检查过了,这对于一级菜单来说非常完美。 我会再等一段时间,看看是否还有其他选项。 - barry

0

我发现这对我的目的很有用。

Private Sub CM_Closing(sender As Object, e As ToolStripDropDownClosingEventArgs) Handles CM.Closing
    If e.CloseReason = ToolStripDropDownCloseReason.ItemClicked Then
        Dim ItemClicked As String = CM.GetItemAt(New Point(Cursor.Position.X - CM.Left, Cursor.Position.Y - CM.Top)).Name
        If ItemClicked = "CMHeader" Then
            e.Cancel = True
        End If
    End If
End Sub

你可以使用 ItemClicked 来读取标签或其他属性。
我只想要一个简单的项目,让用户清楚地知道上下文菜单将影响哪个项目。

0

我发现在没有闪烁的情况下实现这一点的最佳方法是使用DropDown菜单中每个按钮的MouseDown和MouseLeave事件。

例如:

Private Sub ToolStripMenuItem2_Mousedown(sender As Object, e As EventArgs) Handles ToolStripMenuItem2.MouseDown
        ΥπηρεσίεςToolStripMenuItem.DropDown.AutoClose = False
End Sub

Private Sub ToolStripMenuItem2_MouseLeave(sender As Object, e As EventArgs) Handles ToolStripMenuItem2.MouseLeave
        ΥπηρεσίεςToolStripMenuItem.DropDown.AutoClose = True
End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接