source: Common/ListViewComparer.cs

Last change on this file was 14, checked in by chronos, 21 months ago
  • Modified: Various improvements.
File size: 9.7 KB
Line 
1using System;
2using System.Windows.Forms;
3using System.Runtime.InteropServices;
4using System.Collections;
5
6namespace Common
7{
8 public enum ColumnDataType { String, Integer, DateTime, Decimal, Custom };
9
10 // Supports sorting by column in ascending or descending order
11 public class ListViewItemComparer : IComparer
12 {
13 private int column;
14 private SortOrder order;
15
16 public void ColumnClick(int newColumn)
17 {
18 // Determine if clicked column is already the column that is being sorted.
19 if (newColumn == column)
20 {
21 // Reverse the current sort direction for this column.
22 if (order == SortOrder.Ascending)
23 {
24 order = SortOrder.Descending;
25 }
26 else
27 {
28 order = SortOrder.Ascending;
29 }
30 }
31 else
32 {
33 // Set the column number that is to be sorted; default to ascending.
34 column = newColumn;
35 order = SortOrder.Ascending;
36 }
37 }
38
39 public void SetColumn(int newColumn)
40 {
41 column = newColumn;
42 }
43
44 public void SetOrder(SortOrder newOrder)
45 {
46 order = newOrder;
47 }
48
49 public ListViewItemComparer()
50 {
51 column = -1;
52 order = SortOrder.None;
53 }
54
55 public delegate int CompareItemEventHandler(ListViewItem x, ListViewItem y, int column);
56
57 public event CompareItemEventHandler OnCompareItem;
58
59 public int Compare(object x, object y)
60 {
61 ListViewItem listViewItemX = (ListViewItem)x;
62 ListViewItem listViewItemY = (ListViewItem)y;
63
64 int result = 0;
65 if (listViewItemX != null && listViewItemY != null)
66 {
67 if (column < listViewItemX.SubItems.Count && column < listViewItemY.SubItems.Count && column >= 0)
68 {
69 ColumnDataType dataType = ColumnDataType.String;
70
71 if (listViewItemX.ListView.Columns[column].Tag != null)
72 {
73 dataType = (ColumnDataType) (listViewItemX.ListView.Columns[column].Tag);
74 }
75
76 if (dataType == ColumnDataType.Integer)
77 {
78 if (int.TryParse(listViewItemX.SubItems[column].Text, out var xi) &&
79 int.TryParse(listViewItemY.SubItems[column].Text, out var yi))
80 {
81 if (xi < yi) result = -1;
82 else if (xi > yi) result = 1;
83 else result = 0;
84 }
85 }
86 else if (dataType == ColumnDataType.Decimal)
87 {
88 if (decimal.TryParse(listViewItemX.SubItems[column].Text, out var xi) &&
89 decimal.TryParse(listViewItemY.SubItems[column].Text, out var yi))
90 {
91 if (xi < yi) result = -1;
92 else if (xi > yi) result = 1;
93 else result = 0;
94 }
95 }
96 else if (dataType == ColumnDataType.DateTime)
97 {
98 if (DateTime.TryParse(listViewItemX.SubItems[column].Text, out var xi) &&
99 DateTime.TryParse(listViewItemY.SubItems[column].Text, out var yi))
100 {
101 result = DateTime.Compare(xi, yi);
102 }
103 }
104 else if (dataType == ColumnDataType.Custom)
105 {
106 if (OnCompareItem != null)
107 {
108 result = OnCompareItem(listViewItemX, listViewItemY, column);
109 }
110 }
111 else
112 result = string.CompareOrdinal(listViewItemX.SubItems[column].Text,
113 listViewItemY.SubItems[column].Text);
114 }
115 else
116 {
117 if (!listViewItemX.Selected && listViewItemY.Selected) result = 1;
118 else if (listViewItemX.Selected && !listViewItemY.Selected) result = -1;
119 }
120 }
121
122 switch (order)
123 {
124 case SortOrder.Ascending:
125 return result;
126 case SortOrder.Descending:
127 return -result;
128 default:
129 return 0;
130 }
131 }
132
133 public static void ConfigureListView(ListView listView, int column = -1, SortOrder order = SortOrder.None)
134 {
135 if (listView.ListViewItemSorter == null)
136 {
137 listView.ListViewItemSorter = new ListViewItemComparer();
138 }
139
140 ((ListViewItemComparer) listView.ListViewItemSorter).SetOrder(order);
141 ((ListViewItemComparer) listView.ListViewItemSorter).SetColumn(column);
142 if ((column != -1) && (order != SortOrder.None))
143 {
144 listView.Sort();
145 listView.SetSortIcon(column, order);
146 }
147 listView.ColumnClick += delegate (object sender, ColumnClickEventArgs e)
148 {
149 ((ListViewItemComparer) ((ListView) sender).ListViewItemSorter).ColumnClick(e.Column);
150 ((ListView) sender).Sort();
151 ((ListView) sender).SetSortIcon(((ListViewItemComparer) ((ListView) sender).ListViewItemSorter).column, ((ListViewItemComparer) ((ListView) sender).ListViewItemSorter).order);
152 };
153 }
154
155 public static void SetColumnDataType(ListView listView, int index, ColumnDataType dataType)
156 {
157 listView.Columns[index].Tag = dataType;
158 }
159 }
160
161 internal static class ListViewExtensions
162 {
163 [StructLayout(LayoutKind.Sequential)]
164 public struct LVCOLUMN
165 {
166 public Int32 mask;
167 public Int32 cx;
168 [MarshalAs(UnmanagedType.LPTStr)]
169 public string pszText;
170 public IntPtr hbm;
171 public Int32 cchTextMax;
172 public Int32 fmt;
173 public Int32 iSubItem;
174 public Int32 iImage;
175 public Int32 iOrder;
176 }
177
178 const Int32 HDI_WIDTH = 0x0001;
179 const Int32 HDI_HEIGHT = HDI_WIDTH;
180 const Int32 HDI_TEXT = 0x0002;
181 const Int32 HDI_FORMAT = 0x0004;
182 const Int32 HDI_LPARAM = 0x0008;
183 const Int32 HDI_BITMAP = 0x0010;
184 const Int32 HDI_IMAGE = 0x0020;
185 const Int32 HDI_DI_SETITEM = 0x0040;
186 const Int32 HDI_ORDER = 0x0080;
187 const Int32 HDI_FILTER = 0x0100;
188
189 const Int32 HDF_LEFT = 0x0000;
190 const Int32 HDF_RIGHT = 0x0001;
191 const Int32 HDF_CENTER = 0x0002;
192 const Int32 HDF_JUSTIFYMASK = 0x0003;
193 const Int32 HDF_RTLREADING = 0x0004;
194 const Int32 HDF_OWNERDRAW = 0x8000;
195 const Int32 HDF_STRING = 0x4000;
196 const Int32 HDF_BITMAP = 0x2000;
197 const Int32 HDF_BITMAP_ON_RIGHT = 0x1000;
198 const Int32 HDF_IMAGE = 0x0800;
199 const Int32 HDF_SORTUP = 0x0400;
200 const Int32 HDF_SORTDOWN = 0x0200;
201
202 const Int32 LVM_FIRST = 0x1000; // List messages
203 const Int32 LVM_GETHEADER = LVM_FIRST + 31;
204 const Int32 HDM_FIRST = 0x1200; // Header messages
205 const Int32 HDM_SETIMAGELIST = HDM_FIRST + 8;
206 const Int32 HDM_GETIMAGELIST = HDM_FIRST + 9;
207 const Int32 HDM_GETITEM = HDM_FIRST + 11;
208 const Int32 HDM_SETITEM = HDM_FIRST + 12;
209
210 [DllImport("user32.dll")]
211 private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
212
213 [DllImport("user32.dll", EntryPoint = "SendMessage")]
214 private static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, Int32 Msg, IntPtr wParam, ref LVCOLUMN lPLVCOLUMN);
215
216
217 // This method used to set arrow icon
218 public static void SetSortIcon(this ListView listView, int columnIndex, SortOrder order)
219 {
220 IntPtr columnHeader = SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
221
222 for (int columnNumber = 0; columnNumber <= listView.Columns.Count - 1; columnNumber++)
223 {
224 IntPtr columnPtr = new IntPtr(columnNumber);
225 LVCOLUMN lvColumn = new LVCOLUMN {mask = HDI_FORMAT};
226
227 SendMessageLVCOLUMN(columnHeader, HDM_GETITEM, columnPtr, ref lvColumn);
228
229 if (order != SortOrder.None && columnNumber == columnIndex)
230 {
231 switch (order)
232 {
233 case SortOrder.Ascending:
234 lvColumn.fmt &= ~HDF_SORTDOWN;
235 lvColumn.fmt |= HDF_SORTUP;
236 break;
237 case SortOrder.Descending:
238 lvColumn.fmt &= ~HDF_SORTUP;
239 lvColumn.fmt |= HDF_SORTDOWN;
240 break;
241 }
242 lvColumn.fmt |= (HDF_LEFT | HDF_BITMAP_ON_RIGHT);
243 }
244 else
245 {
246 lvColumn.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP & ~HDF_BITMAP_ON_RIGHT;
247 }
248
249 SendMessageLVCOLUMN(columnHeader, HDM_SETITEM, columnPtr, ref lvColumn);
250 }
251 }
252 }
253}
Note: See TracBrowser for help on using the repository browser.