Changeset 15 for Common/ListViewComparer.cs
- Timestamp:
- Jun 18, 2024, 12:15:33 PM (5 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
Common/ListViewComparer.cs
r14 r15 3 3 using System.Runtime.InteropServices; 4 4 using System.Collections; 5 using System.Collections.Generic; 6 using System.Linq; 7 using Microsoft.Win32; 5 8 6 9 namespace Common 7 10 { 8 public enum ColumnDataType { String, Integer, DateTime, Decimal, Custom }; 11 public enum ColumnDataType { String, Integer, DateTime, Decimal, Custom } 12 13 public delegate int ListViewItemCompareEventHandler(ListViewItem x, ListViewItem y); 14 15 public class ListViewColumn 16 { 17 public string Name; 18 public int Width; 19 public HorizontalAlignment TextAlign; 20 public bool Visible; 21 public int FieldIndex; 22 public ColumnDataType DataType; 23 public ListViewItemCompareEventHandler OnCompare; 24 } 9 25 10 26 // Supports sorting by column in ascending or descending order 11 public class ListViewItemComparer : IComparer 27 public class ListViewItemComparer : IComparer, IComparer<ListViewItem> 12 28 { 13 private int column; 14 private SortOrder order; 29 public int Column; 30 public SortOrder Order; 31 public ListView ListView; 32 public ListViewManager ListViewManager; 15 33 16 34 public void ColumnClick(int newColumn) 17 35 { 18 36 // Determine if clicked column is already the column that is being sorted. 19 if (newColumn == column)37 if (newColumn == Column) 20 38 { 21 39 // 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 } 40 Order = Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; 30 41 } 31 42 else 32 43 { 33 44 // Set the column number that is to be sorted; default to ascending. 34 column = newColumn;35 order = SortOrder.Ascending;45 Column = newColumn; 46 Order = SortOrder.Ascending; 36 47 } 37 48 } … … 39 50 public void SetColumn(int newColumn) 40 51 { 41 column = newColumn;52 Column = newColumn; 42 53 } 43 54 44 55 public void SetOrder(SortOrder newOrder) 45 56 { 46 order = newOrder;57 Order = newOrder; 47 58 } 48 59 49 60 public ListViewItemComparer() 50 61 { 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 62 Column = -1; 63 Order = SortOrder.None; 64 } 65 66 public int Compare(ListViewItem x, ListViewItem y) 67 { 68 if (Column >= ListView.Columns.Count) 69 { 70 Column = -1; 71 } 64 72 int result = 0; 65 if (listViewItemX != null && listViewItemY != null) 66 { 67 if (column < listViewItemX.SubItems.Count && column < listViewItemY.SubItems.Count && column >= 0) 68 { 73 if (x != null && y != null) 74 { 75 if (Column < x.SubItems.Count && Column < y.SubItems.Count && Column >= 0) 76 { 77 ListViewColumn listViewColumn = null; 69 78 ColumnDataType dataType = ColumnDataType.String; 70 71 if (listViewItemX.ListView.Columns[column].Tag != null)72 {73 dataType = (ColumnDataType) (listViewItemX.ListView.Columns[column].Tag);79 if (ListView.Columns[Column].Tag != null) 80 { 81 listViewColumn = (ListViewColumn)(ListView.Columns[Column].Tag); 82 dataType = listViewColumn.DataType; 74 83 } 75 84 76 85 if (dataType == ColumnDataType.Integer) 77 86 { 78 if (int.TryParse( listViewItemX.SubItems[column].Text, out varxi) &&79 int.TryParse( listViewItemY.SubItems[column].Text, out varyi))87 if (int.TryParse(x.SubItems[Column].Text, out int xi) && 88 int.TryParse(y.SubItems[Column].Text, out int yi)) 80 89 { 81 90 if (xi < yi) result = -1; … … 86 95 else if (dataType == ColumnDataType.Decimal) 87 96 { 88 if (decimal.TryParse( listViewItemX.SubItems[column].Text, out varxi) &&89 decimal.TryParse( listViewItemY.SubItems[column].Text, out varyi))97 if (decimal.TryParse(x.SubItems[Column].Text, out decimal xi) && 98 decimal.TryParse(y.SubItems[Column].Text, out decimal yi)) 90 99 { 91 100 if (xi < yi) result = -1; … … 96 105 else if (dataType == ColumnDataType.DateTime) 97 106 { 98 if (DateTime.TryParse( listViewItemX.SubItems[column].Text, out varxi) &&99 DateTime.TryParse( listViewItemY.SubItems[column].Text, out varyi))107 if (DateTime.TryParse(x.SubItems[Column].Text, out DateTime xi) && 108 DateTime.TryParse(y.SubItems[Column].Text, out DateTime yi)) 100 109 { 101 110 result = DateTime.Compare(xi, yi); … … 104 113 else if (dataType == ColumnDataType.Custom) 105 114 { 106 if ( OnCompareItem!= null)107 { 108 result = OnCompareItem(listViewItemX, listViewItemY, column);115 if (listViewColumn?.OnCompare != null) 116 { 117 result = listViewColumn.OnCompare(x, y); 109 118 } 110 119 } 111 120 else 112 result = string.CompareOrdinal( listViewItemX.SubItems[column].Text,113 listViewItemY.SubItems[column].Text);121 result = string.CompareOrdinal(x.SubItems[Column].Text, 122 y.SubItems[Column].Text); 114 123 } 115 124 else 116 125 { 117 if (!listViewItemX.Selected && listViewItemY.Selected) result = 1; 118 else if (listViewItemX.Selected && !listViewItemY.Selected) result = -1; 119 } 120 } 121 122 switch (order) 126 if (ListView.VirtualMode) 127 { 128 bool xSelected = ListView.SelectedIndices.IndexOf(x.Index) != -1; 129 bool ySelected = ListView.SelectedIndices.IndexOf(y.Index) != -1; 130 if (!xSelected && ySelected) result = 1; 131 else if (xSelected && !ySelected) result = -1; 132 } 133 else 134 { 135 if (!x.Selected && y.Selected) result = 1; 136 else if (x.Selected && !y.Selected) result = -1; 137 } 138 } 139 } 140 141 switch (Order) 123 142 { 124 143 case SortOrder.Ascending: … … 126 145 case SortOrder.Descending: 127 146 return -result; 147 case SortOrder.None: 128 148 default: 129 149 return 0; … … 131 151 } 132 152 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); 153 public int Compare(object x, object y) 154 { 155 return Compare((ListViewItem)x, (ListViewItem)y); 156 } 157 } 158 159 public class ListViewManager 160 { 161 public List<ListViewColumn> ListColumns; 162 public List<ListViewColumn> VisibleListColumns; 163 public ListView ListView; 164 public List<ListViewItem> ListViewCache; 165 public Dictionary<object, ListViewItem> ListViewDict; 166 private readonly List<ListViewItem> listViewCacheMatched; 167 public delegate void LoadItemHandler(ListViewItem listViewItem, int itemIndex); 168 public event LoadItemHandler LoadItem; 169 public delegate void LoadItemObjectHandler(ListViewItem listViewItem, object item); 170 public event LoadItemObjectHandler LoadItemObject; 171 public delegate bool FilterItemHandler(object item, Dictionary<int, string> filter); 172 public event FilterItemHandler FilterItem; 173 public Dictionary<int, string> Filter; 174 175 public ListViewManager(ListView listView) 176 { 177 ListView = listView; 178 var listViewComparer = new ListViewItemComparer 179 { 180 ListView = listView, 181 ListViewManager = this 182 }; 183 listView.ListViewItemSorter = listViewComparer; 184 185 ListColumns = new List<ListViewColumn>(); 186 foreach (ColumnHeader columnHeader in ListView.Columns) 187 { 188 ListViewColumn listViewColumn = new ListViewColumn() 189 { 190 Name = columnHeader.Text, 191 TextAlign = columnHeader.TextAlign, 192 Width = columnHeader.Width, 193 Visible = true, 194 FieldIndex = Convert.ToInt32(columnHeader.Tag) 195 }; 196 columnHeader.Tag = listViewColumn; 197 ListColumns.Add(listViewColumn); 198 } 199 VisibleListColumns = new List<ListViewColumn>(); 200 if (listView.VirtualMode) 201 { 202 ListViewCache = new List<ListViewItem>(); 203 204 ListView.RetrieveVirtualItem += delegate (object sender, RetrieveVirtualItemEventArgs e) 205 { 206 e.Item = ListViewCache[e.ItemIndex]; 207 }; 208 } 209 ListViewDict = new Dictionary<object, ListViewItem>(); 210 listViewCacheMatched = new List<ListViewItem>(); 211 ListView.ColumnClick += delegate (object sender, ColumnClickEventArgs e) 212 { 213 ((ListViewItemComparer)((ListView)sender).ListViewItemSorter).ColumnClick(e.Column); 214 Sort(); 215 }; 216 Filter = new Dictionary<int, string>(); 217 218 ConfigureListView(); 219 } 220 221 public void Sort() 222 { 223 ListViewItemComparer listViewComparer = (ListViewItemComparer)ListView.ListViewItemSorter; 224 225 if (((ListViewItemComparer)ListView.ListViewItemSorter).Column != -1 && 226 ((ListViewItemComparer)ListView.ListViewItemSorter).Order != SortOrder.None) 227 { 228 229 if (ListView.VirtualMode) 230 { 231 // Store selected items 232 List<object> selectedItems = null; 233 if (ListView.SelectedIndices.Count > 0) 234 { 235 int[] selected = new int[ListView.SelectedIndices.Count]; 236 ListView.SelectedIndices.CopyTo(selected, 0); 237 selectedItems = new List<object>(selected.Length); 238 foreach (int index in ListView.SelectedIndices) 239 { 240 selectedItems.Add(ListViewCache[index].Tag); 241 } 242 } 243 244 ListViewCache.Sort(listViewComparer); 245 ListView.Refresh(); 246 247 // Restore selected items 248 if (selectedItems != null) 249 { 250 ListView.BeginUpdate(); 251 try 252 { 253 ListView.SelectedIndices.Clear(); 254 foreach (var selectedObject in selectedItems) 255 { 256 ListView.SelectedIndices.Add(ListViewCache.IndexOf(ListViewDict[selectedObject])); 257 } 258 } 259 finally 260 { 261 ListView.EndUpdate(); 262 } 263 } 264 } 265 else 266 { 267 ListView.Sort(); 268 } 269 } 270 271 ListView.SetSortIcon(listViewComparer.Column, listViewComparer.Order); 272 } 273 274 public void ReloadCache(int itemCount) 275 { 276 ListView.BeginUpdate(); 277 try 278 { 279 // Sync number of cached items 280 if (listViewCacheMatched.Count > itemCount) listViewCacheMatched.RemoveRange(itemCount, listViewCacheMatched.Count - itemCount); 281 if (listViewCacheMatched.Capacity < itemCount) listViewCacheMatched.Capacity = itemCount; 282 while (listViewCacheMatched.Count < itemCount) 283 { 284 ListViewItem listViewItem = new ListViewItem(); 285 listViewCacheMatched.Add(listViewItem); 286 } 287 288 // Update items content 289 if (LoadItem != null) 290 { 291 for (int i = 0; i < itemCount; i++) 292 { 293 LoadItem?.Invoke(listViewCacheMatched[i], i); 294 } 295 } 296 297 if (Filter.Count > 0 && FilterItem != null) 298 { 299 ListViewCache = listViewCacheMatched.FindAll(x => (bool)FilterItem?.Invoke((object)x.Tag, Filter)).ToList(); 300 } 301 else 302 { 303 ListViewCache = listViewCacheMatched.ToList(); 304 } 305 ListView.VirtualListSize = ListViewCache.Count; 306 307 ListViewDict = ListViewCache.ToDictionary(key => key.Tag, value => value); 308 Sort(); 309 } 310 finally 311 { 312 ListView.EndUpdate(); 313 } 314 } 315 316 public void ReloadCacheItem(ListViewItem listViewItem, int itemIndex) 317 { 318 LoadItem?.Invoke(listViewItem, itemIndex); 319 } 320 321 public void ReloadCacheItemObject(ListViewItem listViewItem, object item) 322 { 323 LoadItemObject?.Invoke(listViewItem, item); 324 } 325 326 public void UpdateFromListView() 327 { 328 // Store current width 329 for (int i = 0; i < VisibleListColumns.Count; i++) 330 { 331 VisibleListColumns[i].Width = ListView.Columns[i].Width; 332 } 333 } 334 335 public void UpdateToListView() 336 { 337 ListView.BeginUpdate(); 338 try 339 { 340 VisibleListColumns = ListColumns.FindAll(x => x.Visible); 341 342 while (ListView.Columns.Count < VisibleListColumns.Count) 343 ListView.Columns.Add(""); 344 while (ListView.Columns.Count > VisibleListColumns.Count) 345 ListView.Columns.RemoveAt(ListView.Columns.Count - 1); 346 for (int i = 0; i < VisibleListColumns.Count; i++) 347 { 348 ColumnHeader item = ListView.Columns[i]; 349 item.Text = VisibleListColumns[i].Name; 350 item.Width = VisibleListColumns[i].Width; 351 item.TextAlign = VisibleListColumns[i].TextAlign; 352 item.Tag = VisibleListColumns[i]; 353 Theme.ApplyTheme(item); 354 } 355 } 356 finally 357 { 358 ListView.EndUpdate(); 359 } 360 } 361 362 public void UpdateColumns() 363 { 364 UpdateFromListView(); 365 UpdateToListView(); 366 } 367 368 public void ConfigureListView(int column = -1, SortOrder order = SortOrder.None) 369 { 370 ListViewItemComparer listViewComparer = (ListViewItemComparer)ListView.ListViewItemSorter; 371 listViewComparer.SetOrder(order); 372 listViewComparer.SetColumn(column); 142 373 if ((column != -1) && (order != SortOrder.None)) 143 374 { 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; 375 Sort(); 376 } 377 } 378 379 public void SetColumnDataType(int fieldIndex, ColumnDataType dataType, ListViewItemCompareEventHandler compareHandler = null) 380 { 381 ListViewColumn column = ListColumns.FirstOrDefault(x => x.FieldIndex == fieldIndex); 382 if (column == null) return; 383 column.DataType = dataType; 384 column.OnCompare = compareHandler; 385 } 386 387 public void SetColumnVisible(int fieldIndex, bool visible) 388 { 389 ListViewColumn column = ListColumns.FirstOrDefault(x => x.FieldIndex == fieldIndex); 390 if (column == null) return; 391 column.Visible = visible; 392 } 393 394 public void LoadFromRegistry(string regSubKey) 395 { 396 RegistryKey regKey = Application.UserAppDataRegistry.OpenSubKey(regSubKey) ?? 397 Application.UserAppDataRegistry.CreateSubKey(regSubKey); 398 399 ListViewItemComparer listViewComparer = (ListViewItemComparer)ListView.ListViewItemSorter; 400 listViewComparer.Order = (SortOrder)regKey.GetValueInt("SortOrder", (int)listViewComparer.Order); 401 listViewComparer.Column = regKey.GetValueInt("SortColumn", listViewComparer.Column); 402 foreach (ListViewColumn listViewColumn in ListColumns) 403 { 404 listViewColumn.Width = regKey.GetValueInt("Width" + listViewColumn.Name, listViewColumn.Width); 405 listViewColumn.Visible = regKey.GetValueBool("Visible" + listViewColumn.Name, listViewColumn.Visible); 406 } 407 UpdateToListView(); 408 } 409 410 public void SaveToRegistry(string regSubKey) 411 { 412 RegistryKey regKey = Application.UserAppDataRegistry.OpenSubKey(regSubKey, true) ?? 413 Application.UserAppDataRegistry.CreateSubKey(regSubKey); 414 415 ListViewItemComparer listViewComparer = (ListViewItemComparer)ListView.ListViewItemSorter; 416 regKey.SetValueInt("SortOrder", (int)listViewComparer.Order); 417 regKey.SetValueInt("SortColumn", listViewComparer.Column); 418 foreach (ListViewColumn listViewColumn in ListColumns) 419 { 420 regKey.SetValueInt("Width" + listViewColumn.Name, listViewColumn.Width); 421 regKey.SetValueBool("Visible" + listViewColumn.Name, listViewColumn.Visible); 422 } 158 423 } 159 424 }
Note:
See TracChangeset
for help on using the changeset viewer.