Не закрывайте ContextMenuStrip при выборе определенных элементов.
-
22-08-2019 - |
Вопрос
Можно ли оставить ContextMenuStrip открытым после выбора/проверки определенных элементов?
Я планирую использовать простой ContextMenuStrip для установки фильтра (таким образом я мог бы использовать тот же фильтр либо в меню, либо в качестве опции, вызываемой щелчком правой кнопкой мыши).
В меню перечислено несколько элементов, и я хотел бы, чтобы пользователь мог выбирать элементы, используя базовую функцию проверки.После завершения выбора пользователь может выбрать параметр «Активировать фильтр» или щелкнуть за пределами меню, чтобы активировать или отменить фильтр.
В случае выбора/щелчка меню обычно закрывается.Можно ли оставить меню открытым при нажатии?
Решение
Чтобы предотвратить закрытие контекстного меню при щелчке элемента, выполните следующие действия.
В событии mousedown для ContextMenuItems установите флаг в значение false, а затем установите его обратно в значение 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
Другие советы
Если будущие программисты задаются вопросом, как это сделать, вот что я выяснил.Это не приведет к закрытию контекстного меню при щелчке по любому элементу.Создайте событие закрытия полосы контекстного меню и настройте оператор if для отмены события закрытия, если причина закрытия выбрана.
private void contextMenuStrip_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
e.Cancel = true;
}
заключительное мероприятие
установите e.Cancel = true, чтобы оставить меню открытым
Единственная проблема заключается в том, что событие не сообщает вам, по какому элементу был сделан щелчок, поэтому вам придется отслеживать это самостоятельно.установите какой-то флаг в событии Click элементов, меню которых вы хотите оставить открытым.затем в событии закрытия проверьте флаг и установите e.Cancel соответствующим образом.
Я не думаю, что в ContextMenuStrip есть свойство для этого.
Обходной путь, который мы используем в нашем приложении, заключается в том, что при нажатии на событие ContextMenuStrip мы выполняем некоторую обработку, а затем, если мы хотим, чтобы контекстное меню оставалось открытым, мы просто вызываем ContextMenuStrip.Show еще раз.
Это будет хорошо работать, если у ContextMenuStrip есть только один уровень.Если есть подменю и подподменю, то вам придется заново выбирать меню, которые были открыты до щелчка, и я не уверен, как это можно сделать...
При закрытии выполните:e.Cancel = e.CloseReason != ToolStripDropDownCloseReason.CloseCalled;а затем, когда вы решите закрыться, вызовите Close().
Это мой метод;он не мерцает и, как мне кажется, немного более гибкий.
Если у вас есть набор 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
Что мне показалось странным, так это то, что 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;
}
}
}
Лучший способ сделать это без мерцания — использовать события 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
Я нашел это полезным для своих целей.
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
чтобы прочитать тег или какое-либо другое свойство.
Мне просто нужен был простой элемент, который давал бы пользователю понять, на какой элемент будет влиять контекстное меню.