-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathListViewUtilities.cs
More file actions
208 lines (124 loc) · 5.71 KB
/
ListViewUtilities.cs
File metadata and controls
208 lines (124 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
using Gsemac.Win32.Native;
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using static Gsemac.Win32.Native.Constants;
namespace Gsemac.Forms {
public static class ListViewUtilities {
// Public members
public static void Sort(ListView listView, int column, SortOrder sortOrder) {
if (listView is null)
throw new ArgumentNullException(nameof(listView));
if (column < 0 || column >= listView.Columns.Count)
throw new ArgumentOutOfRangeException(nameof(column));
listView.BeginUpdate();
try {
// Temporarily set the ListViewItemSorter to null to avoid sorting when Sorting is called.
listView.ListViewItemSorter = null;
listView.Sorting = sortOrder;
listView.ListViewItemSorter = new ListViewItemComparer(column, sortOrder);
if (sortOrder != SortOrder.None)
listView.Sort();
SetColumnSortIcon(listView, column, sortOrder, useNativeSortIcon: true);
}
finally {
listView.EndUpdate();
}
}
public static SortOrder GetNextSortOrder(SortOrder sortOrder) {
switch (sortOrder) {
case SortOrder.Ascending:
return SortOrder.Descending;
case SortOrder.Descending:
return SortOrder.None;
case SortOrder.None:
return SortOrder.Ascending;
default:
return SortOrder.None;
}
}
public static void SetHeaderSortingEnabled(ListView listView, bool enabled) {
// This prevents us from adding the event handler twice.
listView.ColumnClick -= ListViewColumnClickEventHandler;
if (enabled) {
foreach (var pair in listView.Items.Cast<ListViewItem>().Select((item, index) => Tuple.Create(item, index))) {
if (pair.Item1.Tag is null)
pair.Item1.Tag = pair.Item2;
}
listView.ColumnClick += ListViewColumnClickEventHandler;
}
}
// Private members
private const char AscendingArrow = '▲';
private const char DescendingArrow = '▼';
private static void SetColumnSortIcon(ListView listView, int column, SortOrder sortOrder, bool useNativeSortIcon) {
if (column >= 0 && column < listView.Columns.Count) {
if (useNativeSortIcon) {
SetNativeColumnSortIcon(listView, column, sortOrder);
}
else {
SetStringColumnSortIcon(listView, column, sortOrder);
}
}
}
private static void SetNativeColumnSortIcon(ListView listView, int column, SortOrder sortOrder) {
IntPtr columnHeader = User32.SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
for (int columnIndex = 0; columnIndex < listView.Columns.Count; ++columnIndex) {
var columnPtr = new IntPtr(columnIndex);
HDItemA item = new HDItemA() {
mask = HDI_FORMAT,
};
if (User32.SendMessage(columnHeader, HDM_GETITEM, columnPtr, ref item) == IntPtr.Zero)
throw new Win32Exception();
item.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP;
if (sortOrder != SortOrder.None && columnIndex == column) {
switch (sortOrder) {
case SortOrder.Ascending:
item.fmt |= HDF_SORTUP;
break;
case SortOrder.Descending:
item.fmt |= HDF_SORTDOWN;
break;
}
}
if (User32.SendMessage(columnHeader, HDM_SETITEM, columnPtr, ref item) == IntPtr.Zero)
throw new Win32Exception();
}
}
private static void SetStringColumnSortIcon(ListView listView, int column, SortOrder sortOrder) {
for (int columnIndex = 0; columnIndex < listView.Columns.Count; ++columnIndex) {
string columnText = (listView.Columns[columnIndex].Text ?? "")
.Trim(' ', AscendingArrow, DescendingArrow);
if (sortOrder != SortOrder.None && columnIndex == column) {
switch (sortOrder) {
case SortOrder.Ascending:
columnText += " " + AscendingArrow;
break;
case SortOrder.Descending:
columnText += " " + DescendingArrow;
break;
}
}
listView.Columns[columnIndex].Text = columnText;
}
}
private static void ListViewColumnClickEventHandler(object sender, ColumnClickEventArgs e) {
if (sender is ListView listView) {
SortOrder sortOrder = listView.Sorting;
switch (sortOrder) {
case SortOrder.None:
sortOrder = SortOrder.Ascending;
break;
case SortOrder.Ascending:
sortOrder = SortOrder.Descending;
break;
case SortOrder.Descending:
sortOrder = SortOrder.None;
break;
}
Sort(listView, e.Column, sortOrder);
}
}
}
}