ListViewExtension.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10. namespace ListViewNativeArrowIconPoC
  11. {
  12. internal static class ListViewExtension
  13. {
  14. // ReSharper disable InconsistentNaming
  15. // ReSharper disable UnusedMember.Local
  16. private const Int32 HDI_WIDTH = 0x0001;
  17. private const Int32 HDI_HEIGHT = HDI_WIDTH;
  18. private const Int32 HDI_TEXT = 0x0002;
  19. private const Int32 HDI_FORMAT = 0x0004;
  20. private const Int32 HDI_LPARAM = 0x0008;
  21. private const Int32 HDI_BITMAP = 0x0010;
  22. private const Int32 HDI_IMAGE = 0x0020;
  23. private const Int32 HDI_DI_SETITEM = 0x0040;
  24. private const Int32 HDI_ORDER = 0x0080;
  25. private const Int32 HDI_FILTER = 0x0100;
  26. private const Int32 HDF_LEFT = 0x0000;
  27. private const Int32 HDF_RIGHT = 0x0001;
  28. private const Int32 HDF_CENTER = 0x0002;
  29. private const Int32 HDF_JUSTIFYMASK = 0x0003;
  30. private const Int32 HDF_RTLREADING = 0x0004;
  31. private const Int32 HDF_OWNERDRAW = 0x8000;
  32. private const Int32 HDF_STRING = 0x4000;
  33. private const Int32 HDF_BITMAP = 0x2000;
  34. private const Int32 HDF_BITMAP_ON_RIGHT = 0x1000;
  35. private const Int32 HDF_IMAGE = 0x0800;
  36. private const Int32 HDF_SORTUP = 0x0400;
  37. private const Int32 HDF_SORTDOWN = 0x0200;
  38. private const Int32 LVM_FIRST = 0x1000; // List messages
  39. private const Int32 LVM_GETHEADER = LVM_FIRST + 31;
  40. private const Int32 HDM_FIRST = 0x1200; // Header messages
  41. private const Int32 HDM_SETIMAGELIST = HDM_FIRST + 8;
  42. private const Int32 HDM_GETIMAGELIST = HDM_FIRST + 9;
  43. private const Int32 HDM_GETITEM = HDM_FIRST + 11;
  44. private const Int32 HDM_SETITEM = HDM_FIRST + 12;
  45. // ReSharper restore UnusedMember.Local
  46. // ReSharper restore InconsistentNaming
  47. [DllImport("user32.dll")]
  48. private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
  49. [DllImport("user32.dll", EntryPoint = "SendMessage")]
  50. private static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, Int32 msg, IntPtr wParam, ref LVCOLUMN lPlvcolumn);
  51. //This method used to set arrow icon
  52. public static void SetSortIcon(this ListView listView, int columnIndex, SortOrder order)
  53. {
  54. var columnHeader = SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
  55. for (var columnNumber = 0; columnNumber <= listView.Columns.Count - 1; columnNumber++)
  56. {
  57. var columnPtr = new IntPtr(columnNumber);
  58. var lvColumn = new LVCOLUMN { mask = HDI_FORMAT };
  59. SendMessageLVCOLUMN(columnHeader, HDM_GETITEM, columnPtr, ref lvColumn);
  60. if (order != SortOrder.None && columnNumber == columnIndex)
  61. {
  62. switch (order)
  63. {
  64. case SortOrder.Ascending:
  65. lvColumn.fmt &= ~HDF_SORTDOWN;
  66. lvColumn.fmt |= HDF_SORTUP;
  67. break;
  68. case SortOrder.Descending:
  69. lvColumn.fmt &= ~HDF_SORTUP;
  70. lvColumn.fmt |= HDF_SORTDOWN;
  71. break;
  72. }
  73. lvColumn.fmt |= (HDF_LEFT | HDF_BITMAP_ON_RIGHT);
  74. }
  75. else
  76. {
  77. lvColumn.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP & ~HDF_BITMAP_ON_RIGHT;
  78. }
  79. SendMessageLVCOLUMN(columnHeader, HDM_SETITEM, columnPtr, ref lvColumn);
  80. }
  81. }
  82. [StructLayout(LayoutKind.Sequential)]
  83. private struct LVCOLUMN
  84. {
  85. public Int32 mask;
  86. private readonly Int32 cx;
  87. [MarshalAs(UnmanagedType.LPTStr)]
  88. private readonly string pszText;
  89. private readonly IntPtr hbm;
  90. private readonly Int32 cchTextMax;
  91. public Int32 fmt;
  92. private readonly Int32 iSubItem;
  93. private readonly Int32 iImage;
  94. private readonly Int32 iOrder;
  95. }
  96. }
  97. public class ColumnSorter : IComparer
  98. {
  99. private readonly Comparer _listViewItemComparer;
  100. private int _sortColumn;
  101. private SortOrder _sortOrder;
  102. public ColumnSorter()
  103. {
  104. _sortColumn = 0;
  105. _sortOrder = SortOrder.None;
  106. _listViewItemComparer = new Comparer(CultureInfo.CurrentUICulture);
  107. }
  108. public int SortColumn
  109. {
  110. set { _sortColumn = value; }
  111. get { return _sortColumn; }
  112. }
  113. public SortOrder Order
  114. {
  115. set { _sortOrder = value; }
  116. get { return _sortOrder; }
  117. }
  118. /// <summary>
  119. /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive
  120. /// comparison.
  121. /// </summary>
  122. /// <param name="x">First object to be compared</param>
  123. /// <param name="y">Second object to be compared</param>
  124. /// <returns>
  125. /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater
  126. /// than 'y'
  127. /// </returns>
  128. public int Compare(object x, object y)
  129. {
  130. try
  131. {
  132. var lviX = (ListViewItem)x;
  133. var lviY = (ListViewItem)y;
  134. int compareResult;
  135. if (lviX.SubItems[_sortColumn].Tag != null && lviY.SubItems[_sortColumn].Tag != null)
  136. {
  137. compareResult = _listViewItemComparer.Compare(lviX.SubItems[_sortColumn].Tag,
  138. lviY.SubItems[_sortColumn].Tag);
  139. }
  140. else
  141. {
  142. compareResult = _listViewItemComparer.Compare(lviX.SubItems[_sortColumn].Text,
  143. lviY.SubItems[_sortColumn].Text);
  144. }
  145. if (_sortOrder == SortOrder.Ascending)
  146. {
  147. return compareResult;
  148. }
  149. if (_sortOrder == SortOrder.Descending)
  150. {
  151. return (-compareResult);
  152. }
  153. return 0;
  154. }
  155. catch
  156. {
  157. return 0;
  158. }
  159. }
  160. }
  161. }