Как переключать отображение ContextMenuStrip, используя нажатие кнопки, но также позволяя ему нормально закрываться (щелчки элементов меню, потеря фокуса и т. Д.)
Я создал простой UserControl, состоящий из Label и ContextMenuStrip. Я сделал это как ComboBox, но вместо раскрывающегося списка я отображаю ContextMenuStrip.
У меня это работает, но есть некоторая хитрость, которую я не могу понять.
Я пытаюсь заставить ярлык ComboButton работать так же, как ComboBox. Нажмите на кнопку, появится выпадающий список. Нажмите кнопку во второй раз, и она будет убрана. Проблема в том, что ContextMenu исчезает при любом щелчке мыши. Поэтому, когда я нажимаю кнопку второй раз, чтобы убрать меню, меню сначала исчезает, а затем запускается событие щелчка, снова отображая меню.
Я по-прежнему хочу, чтобы меню исчезало, когда пользователь выбирает элемент меню и когда он просто щелкает в любом месте формы, как это делает обычное контекстное меню.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Windows.Forms.VisualStyles;
using System.Diagnostics;
namespace Controls
{
public partial class CMenu : UserControl
{
ButtonState _buttonState = ButtonState.Normal;
public CMenu()
{
InitializeComponent();
}
private void lblSelect_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
ControlPaint.DrawComboButton(e.Graphics, getLabelRect(), _buttonState);
}
private bool IsDropdownHit(MouseEventArgs e)
{
Rectangle cursor = new Rectangle(e.X, e.Y, 1, 1);
if (e.Button == MouseButtons.Left && cursor.IntersectsWith(getLabelRect()))
{
return true;
}
return false;
}
private void lblSelect_MouseUp(object sender, MouseEventArgs e)
{
if (!IsDropdownHit(e))
return;
if (!cmsItems.Visible)
lblSelect.ContextMenuStrip = cmsItems;
cmsItems.Width = lblSelect.Width;
cmsItems.Show(lblSelect, 0, lblSelect.Height);
}
private Rectangle getLabelRect()
{
return new Rectangle(lblSelect.Width - 20, 0, 20, lblSelect.Height);
}
}
}
1 ответ
Итак, я немного переписал вашу мышку:
private void lblSelect_MouseUp(object sender, MouseEventArgs e)
{
if (IsDropdownHit(e) && cmsItems.Tag == null)
{
cmsItems.Width = lblSelect.Width;
cmsItems.Show(lblSelect, 0, lblSelect.Height);
cmsItems.Tag = "Shown";
}
else
{
cmsItems.Hide();
cmsItems.Tag = null;
}
}
Теперь он закроется. НО - если вы не используете кнопку, чтобы закрыть, вам придется дважды щелкнуть, чтобы открыть ее, в следующий раз.
Обходной путь для этой "ошибки":
void cmsItems_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
Point c = PointToClient(Cursor.Position);
if (!IsDropdownHit(new MouseEventArgs(MouseButtons.Left, 1, c.X - lblSelect.Location.X, c.Y - lblSelect.Location.Y, 0)))
cmsItems.Tag = null;
}
В зависимости от того, как вы разработали форму, вам может потребоваться настроить MouseEventArgs-Coordinates, чтобы успешно определить Dropdownhits. Я просто добавил элемент управления CMenu в пустую форму.
Для временного решения не забудьте добавить обработчик в конструктор вашего CMenu.cs:
cmsItems.Closed += cmsItems_Closed;