ListView Column Sort Arrow
-
Using DotNet 3.5... I found the following code on the net (I don't remember exactly where, but I do know it's conglomeration of a couple of different examples). It's a
ListView
extension method that's responsible for putting a sort direction arrow in the column header. The problem is that it places the arrow above the column header text and centers the arrow in the column. I've made a couple of attempts to try to get the arrow to be laced on the right side of the column, but nothing has worked. My last attempt was to add the line after theswitch(order)
statement that adds theHDF_BITMAP_ON_RIGHT
flag. Can anyone help?[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListViewExtensions
{
[StructLayout(LayoutKind.Sequential)]
protected struct LVCOLUMN
{
public Int32 mask;
public Int32 cx;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public Int32 iSubItem;
public Int32 iImage;
public Int32 iOrder;
}const Int32 HDI\_WIDTH = 0x0001; const Int32 HDI\_HEIGHT = HDI\_WIDTH; const Int32 HDI\_TEXT = 0x0002; const Int32 HDI\_FORMAT = 0x0004; const Int32 HDI\_LPARAM = 0x0008; const Int32 HDI\_BITMAP = 0x0010; const Int32 HDI\_IMAGE = 0x0020; const Int32 HDI\_DI\_SETITEM = 0x0040; const Int32 HDI\_ORDER = 0x0080; const Int32 HDI\_FILTER = 0x0100; const Int32 HDF\_LEFT = 0x0000; const Int32 HDF\_RIGHT = 0x0001; const Int32 HDF\_CENTER = 0x0002; const Int32 HDF\_JUSTIFYMASK = 0x0003; const Int32 HDF\_RTLREADING = 0x0004; const Int32 HDF\_OWNERDRAW = 0x8000; const Int32 HDF\_STRING = 0x4000; const Int32 HDF\_BITMAP = 0x2000; const Int32 HDF\_BITMAP\_ON\_RIGHT = 0x1000; const Int32 HDF\_IMAGE = 0x0800; const Int32 HDF\_SORTUP = 0x0400; const Int32 HDF\_SORTDOWN = 0x0200; const Int32 LVM\_FIRST = 0x1000; // List messages const Int32 LVM\_GETHEADER = LVM\_FIRST + 31; const Int32 HDM\_FIRST = 0x1200; // Header messages const Int32 HDM\_SETIMAGELIST = HDM\_FIRST + 8; const Int32 HDM\_GETIMAGELIST = HDM\_FIRST + 9; const Int32 HDM\_GETITEM
-
Using DotNet 3.5... I found the following code on the net (I don't remember exactly where, but I do know it's conglomeration of a couple of different examples). It's a
ListView
extension method that's responsible for putting a sort direction arrow in the column header. The problem is that it places the arrow above the column header text and centers the arrow in the column. I've made a couple of attempts to try to get the arrow to be laced on the right side of the column, but nothing has worked. My last attempt was to add the line after theswitch(order)
statement that adds theHDF_BITMAP_ON_RIGHT
flag. Can anyone help?[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListViewExtensions
{
[StructLayout(LayoutKind.Sequential)]
protected struct LVCOLUMN
{
public Int32 mask;
public Int32 cx;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public Int32 iSubItem;
public Int32 iImage;
public Int32 iOrder;
}const Int32 HDI\_WIDTH = 0x0001; const Int32 HDI\_HEIGHT = HDI\_WIDTH; const Int32 HDI\_TEXT = 0x0002; const Int32 HDI\_FORMAT = 0x0004; const Int32 HDI\_LPARAM = 0x0008; const Int32 HDI\_BITMAP = 0x0010; const Int32 HDI\_IMAGE = 0x0020; const Int32 HDI\_DI\_SETITEM = 0x0040; const Int32 HDI\_ORDER = 0x0080; const Int32 HDI\_FILTER = 0x0100; const Int32 HDF\_LEFT = 0x0000; const Int32 HDF\_RIGHT = 0x0001; const Int32 HDF\_CENTER = 0x0002; const Int32 HDF\_JUSTIFYMASK = 0x0003; const Int32 HDF\_RTLREADING = 0x0004; const Int32 HDF\_OWNERDRAW = 0x8000; const Int32 HDF\_STRING = 0x4000; const Int32 HDF\_BITMAP = 0x2000; const Int32 HDF\_BITMAP\_ON\_RIGHT = 0x1000; const Int32 HDF\_IMAGE = 0x0800; const Int32 HDF\_SORTUP = 0x0400; const Int32 HDF\_SORTDOWN = 0x0200; const Int32 LVM\_FIRST = 0x1000; // List messages const Int32 LVM\_GETHEADER = LVM\_FIRST + 31; const Int32 HDM\_FIRST = 0x1200; // Header messages const Int32 HDM\_SETIMAGELIST = HDM\_FIRST + 8; const Int32 HDM\_GETIMAGELIST = HDM\_FIRST + 9; const Int32 HDM\_GETITEM
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;namespace JSOPTest
{
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ExListView
{
[StructLayout(LayoutKind.Sequential)]
private struct LVCOLUMN
{
public Int32 mask;
public Int32 cx;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public Int32 iSubItem;
public Int32 iImage;
public Int32 iOrder;
}private const Int32 HDI\_FORMAT = 0x4; private const Int32 HDF\_SORTUP = 0x400; private const Int32 HDF\_SORTDOWN = 0x200; private const Int32 LVM\_GETHEADER = 0x101f; private const Int32 HDM\_GETITEM = 0x120b; private const Int32 HDM\_SETITEM = 0x120c; \[DllImport("user32.dll")\] private static extern IntPtr SendMessage( IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); \[DllImport("user32.dll", EntryPoint = "SendMessage")\] private static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, Int32 Msg, IntPtr wParam, ref LVCOLUMN lPLVCOLUMN); public static void SetSortIcon(ListView ListViewControl, int ColumnIndex, SortOrder Order) { IntPtr ColumnHeader = SendMessage(ListViewControl.Handle, LVM\_GETHEADER, IntPtr.Zero, IntPtr.Zero); for (int ColumnNumber = 0; ColumnNumber <= ListViewControl.Columns.Count - 1; ColumnNumber++) { IntPtr ColumnPtr = new IntPtr(ColumnNumber); LVCOLUMN lvColumn = new LVCOLUMN(); lvColumn.mask = HDI\_FORMAT; SendMessageLVCOLUMN(ColumnHeader, HDM\_GETITEM, ColumnPtr, ref lvColumn); if (!(Order == SortOrder.None) && ColumnNumber == ColumnIndex) { switch (Order) { case SortOrder.Ascending: lvColumn.fmt &= ~HDF\_SORTDOWN; lvColumn.fmt |= HDF\_SORTUP; break; case SortOrder.Descending: lvColumn.fmt &= ~HDF\_SORTUP; lvColumn.fmt |= HDF\_SORTDOWN; break; } } else { lvColumn.fmt &= ~HDF\_SORTDOWN & ~HDF\_SORTUP; } SendMessageLVCOLUMN(ColumnHeader, HDM\_SETITEM, ColumnPtr, ref lvColumn); } }
}
}
-
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;namespace JSOPTest
{
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ExListView
{
[StructLayout(LayoutKind.Sequential)]
private struct LVCOLUMN
{
public Int32 mask;
public Int32 cx;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public Int32 iSubItem;
public Int32 iImage;
public Int32 iOrder;
}private const Int32 HDI\_FORMAT = 0x4; private const Int32 HDF\_SORTUP = 0x400; private const Int32 HDF\_SORTDOWN = 0x200; private const Int32 LVM\_GETHEADER = 0x101f; private const Int32 HDM\_GETITEM = 0x120b; private const Int32 HDM\_SETITEM = 0x120c; \[DllImport("user32.dll")\] private static extern IntPtr SendMessage( IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); \[DllImport("user32.dll", EntryPoint = "SendMessage")\] private static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, Int32 Msg, IntPtr wParam, ref LVCOLUMN lPLVCOLUMN); public static void SetSortIcon(ListView ListViewControl, int ColumnIndex, SortOrder Order) { IntPtr ColumnHeader = SendMessage(ListViewControl.Handle, LVM\_GETHEADER, IntPtr.Zero, IntPtr.Zero); for (int ColumnNumber = 0; ColumnNumber <= ListViewControl.Columns.Count - 1; ColumnNumber++) { IntPtr ColumnPtr = new IntPtr(ColumnNumber); LVCOLUMN lvColumn = new LVCOLUMN(); lvColumn.mask = HDI\_FORMAT; SendMessageLVCOLUMN(ColumnHeader, HDM\_GETITEM, ColumnPtr, ref lvColumn); if (!(Order == SortOrder.None) && ColumnNumber == ColumnIndex) { switch (Order) { case SortOrder.Ascending: lvColumn.fmt &= ~HDF\_SORTDOWN; lvColumn.fmt |= HDF\_SORTUP; break; case SortOrder.Descending: lvColumn.fmt &= ~HDF\_SORTUP; lvColumn.fmt |= HDF\_SORTDOWN; break; } } else { lvColumn.fmt &= ~HDF\_SORTDOWN & ~HDF\_SORTUP; } SendMessageLVCOLUMN(ColumnHeader, HDM\_SETITEM, ColumnPtr, ref lvColumn); } }
}
}
That's what I started out with. It gives me the sort arrow, but it's positioned above the text, and centered horizontally in the column header. Mine is different only with respect the extra
const
members, the renaming of some of the variables using in the extension method, and the attempted use of the extra flag after theswitch
statement. On a side note, I don't understand why Microsoft would omit this feature (and others) from the list control in the first place. Programmers have always need to add extra code to implement stuff that should - by now - be part of the control itself..45 ACP - because shooting twice is just silly
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001 -
That's what I started out with. It gives me the sort arrow, but it's positioned above the text, and centered horizontally in the column header. Mine is different only with respect the extra
const
members, the renaming of some of the variables using in the extension method, and the attempted use of the extra flag after theswitch
statement. On a side note, I don't understand why Microsoft would omit this feature (and others) from the list control in the first place. Programmers have always need to add extra code to implement stuff that should - by now - be part of the control itself..45 ACP - because shooting twice is just silly
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001That's kind of odd because this is code I ripped out of an old winforms project that I have, and it gave the arrow where you'd expect it. Granted it was a .NET 2 project, but I don't see that as having an effect.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
-
That's kind of odd because this is code I ripped out of an old winforms project that I have, and it gave the arrow where you'd expect it. Granted it was a .NET 2 project, but I don't see that as having an effect.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
I even thought it might have something to do with the orientation of the header text, so I made them all Left, but that didn't have any effect either.
.45 ACP - because shooting twice is just silly
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001 -
That's kind of odd because this is code I ripped out of an old winforms project that I have, and it gave the arrow where you'd expect it. Granted it was a .NET 2 project, but I don't see that as having an effect.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
I created a new project with an unmolested listview control, dropped the code into it, and it still does it. Could it be a Windows 7 thing?
.45 ACP - because shooting twice is just silly
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001 -
I created a new project with an unmolested listview control, dropped the code into it, and it still does it. Could it be a Windows 7 thing?
.45 ACP - because shooting twice is just silly
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001Possibly. I'll try it out later on.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
-
I created a new project with an unmolested listview control, dropped the code into it, and it still does it. Could it be a Windows 7 thing?
.45 ACP - because shooting twice is just silly
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001It's a Windows 7 thing. The icon in Windows 7 appears centred above the text.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
-
Using DotNet 3.5... I found the following code on the net (I don't remember exactly where, but I do know it's conglomeration of a couple of different examples). It's a
ListView
extension method that's responsible for putting a sort direction arrow in the column header. The problem is that it places the arrow above the column header text and centers the arrow in the column. I've made a couple of attempts to try to get the arrow to be laced on the right side of the column, but nothing has worked. My last attempt was to add the line after theswitch(order)
statement that adds theHDF_BITMAP_ON_RIGHT
flag. Can anyone help?[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListViewExtensions
{
[StructLayout(LayoutKind.Sequential)]
protected struct LVCOLUMN
{
public Int32 mask;
public Int32 cx;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public Int32 cchTextMax;
public Int32 fmt;
public Int32 iSubItem;
public Int32 iImage;
public Int32 iOrder;
}const Int32 HDI\_WIDTH = 0x0001; const Int32 HDI\_HEIGHT = HDI\_WIDTH; const Int32 HDI\_TEXT = 0x0002; const Int32 HDI\_FORMAT = 0x0004; const Int32 HDI\_LPARAM = 0x0008; const Int32 HDI\_BITMAP = 0x0010; const Int32 HDI\_IMAGE = 0x0020; const Int32 HDI\_DI\_SETITEM = 0x0040; const Int32 HDI\_ORDER = 0x0080; const Int32 HDI\_FILTER = 0x0100; const Int32 HDF\_LEFT = 0x0000; const Int32 HDF\_RIGHT = 0x0001; const Int32 HDF\_CENTER = 0x0002; const Int32 HDF\_JUSTIFYMASK = 0x0003; const Int32 HDF\_RTLREADING = 0x0004; const Int32 HDF\_OWNERDRAW = 0x8000; const Int32 HDF\_STRING = 0x4000; const Int32 HDF\_BITMAP = 0x2000; const Int32 HDF\_BITMAP\_ON\_RIGHT = 0x1000; const Int32 HDF\_IMAGE = 0x0800; const Int32 HDF\_SORTUP = 0x0400; const Int32 HDF\_SORTDOWN = 0x0200; const Int32 LVM\_FIRST = 0x1000; // List messages const Int32 LVM\_GETHEADER = LVM\_FIRST + 31; const Int32 HDM\_FIRST = 0x1200; // Header messages const Int32 HDM\_SETIMAGELIST = HDM\_FIRST + 8; const Int32 HDM\_GETIMAGELIST = HDM\_FIRST + 9; const Int32 HDM\_GETITEM
Hi! The extention method works pretty good. (I'm on XP and it's on the right of the text) Does anyone know, if there's any chance to set the flag
lvcolumn.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;
instead of
lvColumn.fmt &= ~HDF_SORTDOWN;
lvColumn.fmt |= HDF_SORTUP;and then load a picture (from the C# .resx file for instance) ?? I would like to use the same exact extention, but drawing a custom arrow of my own instead of the system's arrow ... any help appreciated ;)
-
Hi! The extention method works pretty good. (I'm on XP and it's on the right of the text) Does anyone know, if there's any chance to set the flag
lvcolumn.fmt |= HDF_BITMAP|HDF_BITMAP_ON_RIGHT;
instead of
lvColumn.fmt &= ~HDF_SORTDOWN;
lvColumn.fmt |= HDF_SORTUP;and then load a picture (from the C# .resx file for instance) ?? I would like to use the same exact extention, but drawing a custom arrow of my own instead of the system's arrow ... any help appreciated ;)
Edit: It works well with _IMAGE instead of _SORTDOWN or _SORTUP Only problem is that it will remove the other image on the column header (if you dont have any image in your column header, then it's all fine, but if you do, like in my project, well it will be either on the left, or on the right as a sort indicator, but not both. My plan was to leave a column header image on the left, and a small arrow on the right......) Will need to owner draw the full header :/ That's bad because column header's mouse over event are pretty hard to catch.. dont even know how to do so far...... Anyway, if someone has a clue.. :)