2013-07-14 60 views
4

我找不到任何可以帮助我的功能,而且我不想编写疯狂的函数,它会HitTest ListView区域的每个像素,找出需要的列的坐标(如果有可能从列中获取Column的HitTest)。有没有办法确定ListView中左上角的坐标?

enter image description here

由于亚伊尔Nevet评论,我写了下面的函数来确定所需列的左侧位置:

private int GetLeftOfColumn(ColumnHeader column, ListView lv) 
{ 
    if (!lv.Columns.Contains(column)) 
     return -1; 

    int calculated_left = 0; 

    for (int i = 0; i < lv.Columns.Count; i++) 
     if (lv.Columns[i] == column) 
      return calculated_left; 
     else 
      calculated_left += lv.Columns[i].Width + 1; 

    return calculated_left; 
} 
+1

这个问题看起来并不回答。你可以通过pinvoking SendMessage()来获得它。您需要TVM_GETHEADER和HDM_GETITEMRECT。 –

+0

嗯,我至少知道如何去做,并根据Yair Nevet的评论编写了自己的功能。您可以发布准备使用的答案,并且会被接受。 – Kosmos

+0

@HansPassant我很想看到你的解决方案。 –

回答

1

因为USER32消息上面所提到的但没有给出实现,而我只是碰到这种来到时,我需要解决这个问题,这里是一个使用短信到一个工作版本本地代码。

这里是包裹在一个私人NativeMethods类的一些必需的物品:

private static class NativeMethods { 
    private const int LVM_FIRST = 0x1000; 
    private const int LVM_GETHEADER = LVM_FIRST + 31; 

    private const int HDM_FIRST = 0x1200; 
    private const int HDM_GETITEMRECT = HDM_FIRST + 7; 

    private const int SB_HORZ = 0; 
    private const int SB_VERT = 1; 

    private const int SIF_POS = 0x0004; 

    [StructLayout(LayoutKind.Sequential)] 
    public class SCROLLINFO { 
     public int cbSize = Marshal.SizeOf(typeof(NativeMethods.SCROLLINFO)); 
     public int fMask; 
     public int nMin; 
     public int nMax; 
     public int nPage; 
     public int nPos; 
     public int nTrackPos; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct RECT { 
     public int Left; 
     public int Top; 
     public int Right; 
     public int Bottom; 
    } 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); 

    [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)] 
    public static extern IntPtr SendMessageGETRECT(IntPtr hWnd, int Msg, int wParam, ref RECT lParam); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
    public static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, SCROLLINFO scrollInfo); 

    /// <summary> 
    /// Return the handle to the header control on the given list 
    /// </summary> 
    /// <param name="list">The listview whose header control is to be returned</param> 
    /// <returns>The handle to the header control</returns> 
    public static IntPtr GetHeaderControl(ListView list) { 
     return SendMessage(list.Handle, LVM_GETHEADER, 0, 0); 
    } 

    /// <summary> 
    /// Get the scroll position of the given scroll bar 
    /// </summary> 
    /// <param name="lv"></param> 
    /// <param name="horizontalBar"></param> 
    /// <returns></returns> 
    public static int GetScrollPosition(ListView lv, bool horizontalBar) { 
     int fnBar = (horizontalBar ? SB_HORZ : SB_VERT); 

     SCROLLINFO scrollInfo = new SCROLLINFO(); 
     scrollInfo.fMask = SIF_POS; 
     if (GetScrollInfo(lv.Handle, fnBar, scrollInfo)) { 
      return scrollInfo.nPos; 
     } 
     else { 
      return -1; 
     } 
    } 

    /// <summary> 
    /// Return the screen rectangle of the column header item specified 
    /// </summary> 
    /// <param name="handle">Handle to the header control to check</param> 
    /// <param name="index">Index of the column to get</param> 
    /// <returns></returns> 
    public static Rectangle GetHeaderItemRect(IntPtr handle, int index) { 
     RECT rc = new RECT(); 
     IntPtr result = NativeMethods.SendMessageGETRECT(handle, HDM_GETITEMRECT, index, ref rc); 
     if (result != IntPtr.Zero) { 
      return new Rectangle(rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top); 
     } 
     return Rectangle.Empty; 
    } 
} 

下面是得到你的位置代码:

/// <summary> 
/// Get's the location coordinate of the specified column header's top/left corner 
/// </summary> 
/// <param name="oListView">ListView control to get the column header location from</param> 
/// <param name="iColumn">Column to find the location for</param> 
/// <param name="bAsScreenCoordinate">Whether the location returned is for the screen or the local ListView control</param> 
/// <returns>Location of column header or <see cref="Point.Empty"/> if it could not be retrieved</returns> 
public static Point GetColumnHeaderTopLeft(this ListView oListView, int iColumn, bool bAsScreenCoordinate) { 
    if (oListView == null) { 
     throw new ArgumentNullException(); 
    } 
    if ((iColumn < 0) || (iColumn >= oListView.Columns.Count)) { 
     throw new ArgumentOutOfRangeException(); 
    } 

    // Get the header control's rectangle 
    IntPtr hndHeader = NativeMethods.GetHeaderControl(oListView); 
    Rectangle oHeaderRect = NativeMethods.GetHeaderItemRect(hndHeader, iColumn); 
    if (oHeaderRect.IsEmpty) { 
     return Point.Empty; 
    } 

    // Get the scroll bar position to adjust the left 
    int iScroll = NativeMethods.GetScrollPosition(oListView, true); 

    // Create the local coordinate 
    Point oLocation = new Point(oHeaderRect.Left - iScroll, oHeaderRect.Top); 

    // Return the local or screen coordinate 
    return bAsScreenCoordinate ? oListView.PointToScreen(oLocation) : oLocation; 
} 
1

可以为了实现它使用PointToScreenPointToClient类,请看:

Point locationOnForm = listView1.FindForm() 
       .PointToClient(listView1.Parent.PointToScreen(listView1.Location)); 

现在使用接收点的X和Y坐标以及ord中的列宽和高度呃来计算它的形式位置:

private int GetLeftOfColumn(ColumnHeader column, ListView lv) 
{ 
    if (!lv.Columns.Contains(column)) 
     return -1; 

    int calculated_left = 0; 

    for (int i = 0; i < lv.Columns.Count; i++) 
     if (lv.Columns[i] == column) 
      return calculated_left; 
     else 
      calculated_left += lv.Columns[i].Width + 1; 

    return calculated_left; 
} 
+0

从这里我得到至少一些ColumnHeader的坐标吗?它不是控件,也不包含Location字段,与Top和Left相同。 – Kosmos

+1

您可以根据列表视图位置和列宽来计算它。 –

+0

谢谢,这至少是一些想法。不是100%的准确性,因为边界等,但仍然可以使用... – Kosmos

相关问题