如何知道在ListView中右键单击哪个标题列?

时间:2017-02-20 23:36:21

标签: c# listview

我找到了一种方法来处理ListView Header列中的右键单击。

我需要定义一个新的ListView项并覆盖WndProc

public class ListViewUpdated : ListView
{
    public ContextMenuStrip HeaderContextMenu { get; set; }
    private frmMain mainForm;


    public ListViewUpdated()
    {
        mainForm = null;
    }

    public void setAttributes(frmMain frm, ContextMenuStrip menu)
    {
        mainForm = frm;
        HeaderContextMenu = menu;
    }

    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)
            {
                mainForm.Invoke(mainForm.delegateDeleteColumn,
                                  new Object[] { HeaderContextMenu });
            }
        }
    }

    private void InitializeComponent()
    {
        this.SuspendLayout();
        this.ResumeLayout(false);

    }
}

这确实很好用。我使用了一个委托,因此事件触发器可以是表单中的一个函数。

到目前为止,表格中的事件是:

    if (tabControl1.SelectedIndex == 0)
    {
        System.Drawing.Point mousePos = lsvRequestsByParameters.PointToClient(Control.MousePosition);
        hitTest = lsvRequestsByParameters.HitTest(mousePos);
    }
    else
    {
        System.Drawing.Point mousePos = lsvRequestsByParametersToSave.PointToClient(Control.MousePosition);
        hitTest = lsvRequestsByParametersToSave.HitTest(mousePos);
    }
    HeaderContextMenu.Show(Control.MousePosition);

它被正确调用。

它允许我弹出标题上的上下文菜单。

问题是选项之一是删除列:

private void deleteColumnToolStripMenuItem2_Click(object sender, EventArgs e)
{
    int columnIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);
    lsvRequestsByParameters.Columns.RemoveAt(columnIndex);
}

问题如下:

int columnIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);

似乎当我设置hitTest变量时,如果鼠标位于标题之上,则它不会返回可用的内容。请注意,如果单击一个空单元格,以这种方式使用hitTest会正确地返回columnIndex

那么我该怎样做才能获得columnIndex

1 个答案:

答案 0 :(得分:1)

只要Items ListView中有HitTest,您就可以愚弄 Point eLoc = listView1.PointToClient(Control.MousePosition); ListViewHitTestInfo hit = null; int i = 0; do { Point vp = new Point(eLoc.X, listView1.Items[i].Bounds.Top); hit = listView1.HitTest(vp); i++; } while( hit.SubItem == null && i < listView1.Items.Count); var ColumnIndex = hit.Item.SubItems.IndexOf(hit.SubItem); 喂食 的位置>标题..:

SubItems

请注意,只有当Items[0]呈锯齿状时才需要循环。否则,您可以随时前往ListView

<强>更新

如果您有理由想要点击 private List<Rectangle> lvHeaderBounds = new List<Rectangle>(); 的标题,则可以使用此解决方法:

声明一个包含标题的所有边界矩形的变量:

ColumnClick

在上面处理 Point eLoc = listView1.PointToClient(Control.MousePosition); var ColumnIndex = -1; if (listView1.Items.Count == 0) { getHeaders(listView1); for (int i = 0; i < lvHeaderBounds.Count; i++) if (lvHeaderBounds[i].X + lvHeaderBounds[i].Width > eLoc.X) { ColumnIndex = i; break; } } else... 的代码中使用了这个:

ColumHeader

要收集边界矩形,我们需要在void getHeaders(ListView lv) { lvHeaderBounds.Clear(); for (int i = 0; i < lv.Columns.Count; i++) { ColumnHeader ch = lv.Columns[i]; int left = i == 0 ? 0 : lvHeaderBounds[i-1].X + ch.Width; Rectangle r = new Rectangle(left, 0, ch.Width, 0); lvHeaderBounds.Add(r); } } 集合上循环。这是一个实现此功能的功能:

    private void listView1_ColumnReordered(object sender, ColumnReorderedEventArgs e)
    {
        if (lvHeaderBounds != null) lvHeaderBounds.Clear();
        getHeaders(sender as ListView);
    }

    private void listView1_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
    {
        if (lvHeaderBounds != null) lvHeaderBounds.Clear();
        getHeaders(sender as ListView);
    }

当用户或代码修改标题布局时,我们还需要刷新我们的集合:

Height

请注意,列表中的0值均为Share with me folder

另请注意,在我的测试中,即使在调整标题和/或滚动它们之后,代码也能正常工作..