In any case, to determine the coordinates of the upper left corner of a column in a ListView?

I canโ€™t find any function that can help me with this, and I donโ€™t want to write a crazy function that will HitTest for each pixel of the ListView to find out the coordinates of the column (if possible, get a column from HitTest).

enter image description here

Thanks to a comment by Yair Nevet, I wrote the following function to determine the left position of the desired column:

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; } 
+4
source share
2 answers

Since USER32 messages were mentioned above, but the implementation was not given, and I just came across this when I needed to solve it, here is a working version using messaging with native code.

Here are some required elements enclosed in the NativeMethods private class:

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

Here is the code that gets your location:

 /// <summary> /// Get the location coordinate of the specified column header 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 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
source

For this you can use the PointToScreen and PointToClient , look:

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

Now use the X and Y coordinates for the resulting point and the width and height of the column to calculate its position in the form:

 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
source

Source: https://habr.com/ru/post/1491335/


All Articles