How to determine the clicked column index in a Listview

S

Steph.

I have a List view displaying data in Detail mode with several columns.

How I can get the column index the user clicked on ? (when user click on an item inside the ListView, not on a column hearder..)



Thanks for any help !



Steph.
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


Dont remember if you have this info in the listviewitem , otherwise it should be easy to calculate, in the MouseDown event you get the coordinates of the click , a simple math will detect in which column the clicked occurrd.


--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation
I have a List view displaying data in Detail mode with several columns.

How I can get the column index the user clicked on ? (when user click on an item inside the ListView, not on a column hearder..)



Thanks for any help !



Steph.
 
A

Andreas Mueller

Steph. said:
I have a List view displaying data in Detail mode with several columns.

How I can get the column index the user clicked on ? (when user click on
an item inside the ListView, not on a column hearder..)



Thanks for any help !



Steph.

You can use the sub item hittest of the listview. The code below also
takes care about column reordering.

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[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);

private bool HitTest(ListView mListView, 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 = mListView.GetItemAt(hitPoint.X, hitPoint.Y);

if(item != null && mListView.Columns.Count > 1)
{
if(mListView.AllowColumnReorder)
{
int[] columnOrder = new int[mListView.Columns.Count];
// Get the order of columns in case
// they've changed from the user.
if(SendMessage(mListView.Handle,
LVM_COLUMNORDERARRAY, mListView.Columns.Count,
columnOrder) != 0)
{
int i;
// Get the subitem rectangles (except column 0),
// but get them in the proper order.
RECT[] subItemRects = new RECT[mListView.Columns.Count];
for(i = 1; i < mListView.Columns.Count; i++)
{
subItemRects[columnOrder].top = i;
subItemRects[columnOrder].left = LVIR_BOUNDS;
SendMessage(mListView.Handle,
LVM_GETSUBITEMRECT, item.Index,
ref subItemRects[columnOrder]);
}

// Find where column 0 is.
for(i = 0; i < columnOrder.Length; i++)
if(columnOrder == 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.left = subItemRects[i-1].right;
subItemRects.right = subItemRects.left
+ mListView.Columns[0].Width;
}
else
{
// Else, column 0 is at index 0, so use the next.
subItemRects[0].left = subItemRects[1].left -
mListView.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 <= mListView.Columns.Count-1;
index++)
{
subItemRect = new RECT();
subItemRect.top = index;
subItemRect.left = LVIR_BOUNDS;
if(SendMessage(mListView.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;
}

HTH,
Andy
 
S

Steph.

I found a solution.... for Windows.... it works great ! :



class TListViewFFct
{

[StructLayout(LayoutKind.Sequential)] struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}


[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd,
int wMsg , int wParam , ref RECT lParam);


public static int GetListViewSubItem(ListView AListView, Point APoint)
{

const int LVM_FIRST = 0x1000;
const int LVM_GETSUBITEMRECT = (LVM_FIRST + 56);
const int LVIR_BOUNDS = 0;

RECT myrect;
ListViewItem lvitem = AListView.GetItemAt(APoint.X, APoint.Y);
if(lvitem == null && AListView.SelectedItems.Count > 0)
lvitem = AListView.SelectedItems[0];

int intLVSubItemIndex = -1;
ListViewItem.ListViewSubItem LVSubItem = null;

if(lvitem != null)
{
int intSendMessage;
for ( int i = 1; i <= lvitem.SubItems.Count - 1; i++)
{
LVSubItem = lvitem.SubItems;
myrect = new RECT();
myrect.top = i;
myrect.left = LVIR_BOUNDS;
intSendMessage = SendMessage(AListView.Handle, LVM_GETSUBITEMRECT,
lvitem.Index, ref myrect);
if (APoint.X < myrect.left)
{
LVSubItem = lvitem.SubItems[0];
intLVSubItemIndex = 0;
break;
}
else if (APoint.X >= myrect.left & APoint.X <= myrect.right)
{
intLVSubItemIndex = i;
break;
}
else
LVSubItem = null;
}
}
if (LVSubItem == null || lvitem == null)
{
intLVSubItemIndex = -1;
}
return intLVSubItemIndex;
}


}//EndClass TListViewFFct
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top