【问题标题】:ListView ContextMenuStrip for column headers列标题的 ListView ContextMenuStrip
【发布时间】:2013-07-24 15:28:50
【问题描述】:

当我右键单击 ListView 列标题时,我会显示不同的 ContextMenuStrip,而在 ListView 内显示另一个。

class ListViewExx : ListView
{
    public ContextMenuStrip HeaderContextMenu { get; set; }
    int contextMenuSet = 0;
    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc(ref m);
        switch(m.Msg)
        {
            case 0x210: //WM_PARENTNOTIFY
                contextMenuSet = 1;
                break;
            case 0x21:  //WM_MOUSEACTIVATE
                contextMenuSet++;
                break;
            case 0x7b:  //WM_CONTEXTMENU
                if(contextMenuSet == 2 && HeaderContextMenu != null)
                    HeaderContextMenu.Show(Control.MousePosition);
                break;
        }
    }
}

这很好用。问题是我第一次在 ListView 内右键单击 - 显示了标题 contextMenuStrip。

【问题讨论】:

  • 我觉得还有一种简单的方法,我不是很理解你代码中的WM_PARENTNOTIFY和其他消息,看起来WM_PARENTNOTIFY是发送到你的ListView和@987654326 @ 跟随,这使您的contextMenuSet=2。你应该确保这些消息应该在你想要的时间发送,我认为这个解决方案不可靠,应该避免,除非你彻底理解WM_PARENTNOTIFYWM_MOUSEACTIVATE在哪些情况下被发送到你的ListView。跨度>
  • 我对这段代码也不太了解,我在codeproject(在commnents)中找到了它并且运行良好。 codeproject.com/Articles/23330/…

标签: c# winforms listview


【解决方案1】:

依赖激活状态太hacky了。更简单的是,WM_CONTEXTMENU 消息传递生成消息的窗口句柄。因此,您可以简单地将其与列表视图的句柄进行比较。如果它不匹配,那么你知道它是标题控件:

protected override void WndProc(ref System.Windows.Forms.Message m)
{
    base.WndProc(ref m);
    if (m.Msg == 0x7b) {  //WM_CONTEXTMENU
        if (m.WParam != this.Handle) HeaderContextMenu.Show(Control.MousePosition);
    }
}

从技术上讲,您应该使用 LVM_GETHEADER,但这应该可以正常工作。

【讨论】:

  • OP 只想在右击Column HeadersListView 时显示HeaderContextMenu,但这似乎在用户右击ListView 中的任何点时显示它地区?
  • 现在它会在我点击的任何地方显示标题菜单
  • 糟糕,它是 WParam,而不是 LParam。
  • +1 获得了很好的答案,它似乎比写成文章的codeproject 中的解决方案要简单得多?
【解决方案2】:

我尝试找到一种干净的方法来获取ListView 中的Column Header Rectangle,以检查用户右键单击的点是否在Column Header 中。但是,我刚刚发现ListViewColumn Header Rectangle 似乎只在DrawColumnHeader 事件处理程序中显示。这个解决方案是我能想到的所有可以帮助你的方法:

public class CustomListView : ListView
{
    //This contains the Column Index and its corresponding Rectangle in screen coordinates.
    Dictionary<int, Rectangle> columns = new Dictionary<int, Rectangle>();
    public CustomListView()
    {
        OwnerDraw = true;//This will help the OnDrawColumnHeader be called.
    }
    protected override void OnDrawItem(DrawListViewItemEventArgs e)
    {
        e.DrawDefault = true;
        base.OnDrawItem(e);
    }
    protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
    {
        e.DrawDefault = true;
        base.OnDrawSubItem(e);
    }
    protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
    {
        columns[e.ColumnIndex] = RectangleToScreen(e.Bounds);
        e.DrawDefault = true;
        base.OnDrawColumnHeader(e);
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x7b)//WM_CONTEXTMENU
        {
            int lp = m.LParam.ToInt32();
            int x = ((lp << 16) >> 16);
            int y = lp >> 16;
            foreach (KeyValuePair<int, Rectangle> p in columns)
            {
                if (p.Value.Contains(new Point(x, y)))
                {
                    //MessageBox.Show(Columns[p.Key].Text); <-- Try this to test if you want.
                    //Show your HeaderContextMenu corresponding to a Column here.
                    break;
                }
            }                
        }
        base.WndProc(ref m);
    }
}

【讨论】:

  • 如果每列需要不同的ContextMenu,至少这个解决方案可以工作:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-24
  • 2011-06-27
相关资源
最近更新 更多