![]() |
Desktop Development »
List Controls »
ListView controls
Intermediate
A ListView HitTest for C#By row4utcAn article on adding a HitTest method for a ListView control. |
C#, Windows, .NET 1.0, .NET 1.1VS.NET2003, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

For those of you who are making the move from C++ to C#, you may be looking for a HitTest method such as the one commonly found around the web for C++. A HitTest method is a method used on C#'s ListView control (CListCtrl in C++/MFC) that when the mouse is clicked on the control, gives the programmer the row and column numbers where the mouse was clicked. At first, this was very basic. But, as I got responses from it for certain cases that would not work, the code became a littler more involved. Anyway, here is the latest.
Simply add a ListView control to a Form, add some columns, and be sure to...
ListView "View" property to Details (HitTest pointless otherwise).
ListView "Full Row Select" property to true (If not, HitTest fails on all but first column).
false if clicked on non-existent row).
For the HitTest to work properly, we must add a few other things to your class. First, we must add a structure to our class. Somewhere inside your class definition, add the code below to be able to create "C++ - like" RECT objects.
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
Next, we must add some messaging methods. We must add a SendMessage method that will allow us to get each subitem's bounding rectangle. A different parameterized SendMessage method must be added to allow us to get the column order array for the case that the columns in the ListView have been reordered by the user.
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd,
int msg , int wParam , ref RECT lParam);
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd,
int msg , int wParam , int[] lParam);
Lastly, the HitTest method is as follows...
private bool HitTest(Point hitPoint, out int row, out int column)
{
const int LVM_GETSUBITEMRECT = 0x1038; //Is LVM_FIRST (0x1000) + 56
const int LVM_COLUMNORDERARRAY = 0x103B; //Is LVM_FIRST (0x1000) + 59
const int LVIR_BOUNDS = 0;
bool retval = false;
RECT subItemRect;
row = column = -1;
ListViewItem item = m_lvListView.GetItemAt(hitPoint.X, hitPoint.Y);
if(item != null && m_lvListView.Columns.Count > 1)
{
if(m_lvListView.AllowColumnReorder)
{
int[] columnOrder = new int[m_lvListView.Columns.Count];
// Get the order of columns in case
// they've changed from the user.
if(SendMessage(m_lvListView.Handle,
LVM_COLUMNORDERARRAY, m_lvListView.Columns.Count,
columnOrder) != 0)
{
int i;
// Get the subitem rectangles (except column 0),
// but get them in the proper order.
RECT[] subItemRects = new RECT[m_lvListView.Columns.Count];
for(i = 1; i < m_lvListView.Columns.Count; i++)
{
subItemRects[columnOrder[i]].top = i;
subItemRects[columnOrder[i]].left = LVIR_BOUNDS;
SendMessage(m_lvListView.Handle,
LVM_GETSUBITEMRECT, item.Index,
ref subItemRects[columnOrder[i]]);
}
// Find where column 0 is.
for(i = 0; i < columnOrder.Length; i++)
if(columnOrder[i] == 0)
break;
// Fix column 0 since we can't get
// the rectangle bounds of it using above.
if(i > 0)
{
// If column 0 not at index 0, set using the previous.
subItemRects[i].left = subItemRects[i-1].right;
subItemRects[i].right = subItemRects[i].left
+ m_lvListView.Columns[0].Width;
}
else
{
// Else, column 0 is at index 0, so use the next.
subItemRects[0].left = subItemRects[1].left -
m_lvListView.Columns[0].Width;
subItemRects[0].right = subItemRects[1].left;
}
// Go through the subitem rectangle bounds and
// see where our point is.
for(int index = 0; index < subItemRects.Length; index++)
{
if(hitPoint.X >= subItemRects[index].left &
hitPoint.X <= subItemRects[index].right)
{
row = item.Index;
column = columnOrder[index];
retval = true;
break;
}
}
}
}
// No column reordering...much simpler.
else
{
for(int index = 1; index <= m_lvListView.Columns.Count-1;
index++)
{
subItemRect = new RECT();
subItemRect.top = index;
subItemRect.left = LVIR_BOUNDS;
if(SendMessage(m_lvListView.Handle,
LVM_GETSUBITEMRECT, item.Index, ref subItemRect) != 0)
{
if(hitPoint.X < subItemRect.left)
{
row = item.Index;
column = 0;
retval = true;
break;
}
if(hitPoint.X >= subItemRect.left & hitPoint.X <=
subItemRect.right)
{
row = item.Index;
column = index;
retval = true;
break;
}
}
}
}
}
return retval;
}
HitTest test application 1.0.0.
HitTest test application 1.0.1.
HitTest test application 2.0.0.
ListView control is horizontally scrolled.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 27 Jan 2004 Editor: Nishant Sivakumar |
Copyright 2004 by row4utc Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |