1

メニューの一部の項目に複数の項目が含まれる ContextMenu を作成しようとしています。ToolStrip と ContextMenuItem を結合しようとしているように見えます。ToolStripControlHost を使用してみましたが、フォーカスに問題が生じます。基本的に、ToolStrip 内のすべてを 2 回クリックする必要があります。

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

これを達成する方法について何か考えはありますか?

4

1 に答える 1

1

ContextMenuStrip は、コンテキスト メニューのように機能しないカスタム ポップアップ ウィンドウのターゲットとしては魅力的すぎます。ユーザーがメニューの外側をクリックすると自動的にポップアップするため、望ましいです。ただし、制限はありますが、制御ホストとしてはあまり優れていません。クリックの問題は古典的なもので、CMS はマウスをキャプチャして、ユーザーがウィンドウの外をクリックしたことを検出します。

これは本当にフォームのはずです。ただし、CMS と同じ動作をさせるには、少し作業が必要です。ウィンドウを非表示にするには、ウィンドウの外にあるマウス クリックを検出する必要があります。CMS のようにマウスをキャプチャしても機能しません。トリックの 1 つは 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 とは異なり、アプリケーションが所有するウィンドウをクリックした場合にのみフォームがポップアップすることに注意してください。機能であり、バグではありません。

于 2011-03-06T01:09:59.337 に答える