2013-07-14 63 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

相關問題