.NET Multiple ToolStripButtons в одном ContextMenuItem - PullRequest
1 голос
/ 06 марта 2011

Я пытаюсь создать ContextMenu, в котором некоторые элементы меню содержат более одного элемента. Вы можете увидеть это как попытку объединить ToolStrip и ContextMenuItem. Я пытался использовать ToolStripControlHost, но это создает проблемы с фокусом. Это в основном требует, чтобы вы дважды щелкнули все в ToolStrip ..

ContextMenuStrip m = new ContextMenuStrip();
ToolStrip tStrip = new ToolStrip(new ToolStripDropDownButton(), new ToolStripButton());
ToolStripControlHost tsHost = new ToolStripControlHost(tStrip);
m.Items.Add(tsHost);

Есть мысли о том, как этого добиться?

1 Ответ

1 голос
/ 06 марта 2011

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. Функция, а не ошибка.

...