ListView ContextMenuStrip for column headers

半腔热情 提交于 2020-02-01 08:50:13

问题


I display a different ContextMenuStrip when I right click the ListView column header, and another inside 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;
        }
    }
}

This works very well. The problem is the FIRST TIME I right click inside the ListView - the headers contextMenuStrip is shown.


回答1:


Relying on the activation state is too hacky. It is far simpler, the WM_CONTEXTMENU message passes the handle of the window that generated the message. So you can simply compare it to the handle of the listview. If it doesn't match then you know it was the header control:

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);
    }
}

Technically you should use LVM_GETHEADER but this should work just fine.




回答2:


I've tried finding a clean way to get Column Header Rectangle of a ListView to check if the Point at which user right-clicks is in a Column Header or not. However, I've just found that the Column Header Rectangle of a ListView seems to be revealed only in a DrawColumnHeader event handler. This solution is all what I can think of to help you out:

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);
    }
}


来源:https://stackoverflow.com/questions/17838494/listview-contextmenustrip-for-column-headers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!