Ignore:
Timestamp:
Jun 18, 2024, 12:15:33 PM (5 months ago)
Author:
chronos
Message:
  • Modified: Updated files.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • Common/ListViewComparer.cs

    r14 r15  
    33using System.Runtime.InteropServices;
    44using System.Collections;
     5using System.Collections.Generic;
     6using System.Linq;
     7using Microsoft.Win32;
    58
    69namespace Common
    710{
    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    }
    925
    1026    // Supports sorting by column in ascending or descending order
    11     public class ListViewItemComparer : IComparer
     27    public class ListViewItemComparer : IComparer, IComparer<ListViewItem>
    1228    {
    13         private int column;
    14         private SortOrder order;
     29        public int Column;
     30        public SortOrder Order;
     31        public ListView ListView;
     32        public ListViewManager ListViewManager;
    1533
    1634        public void ColumnClick(int newColumn)
    1735        {
    1836            // Determine if clicked column is already the column that is being sorted.
    19             if (newColumn == column)
     37            if (newColumn == Column)
    2038            {
    2139                // 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;
    3041            }
    3142            else
    3243            {
    3344                // 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;
    3647            }
    3748        }
     
    3950        public void SetColumn(int newColumn)
    4051        {
    41             column = newColumn;
     52            Column = newColumn;
    4253        }
    4354
    4455        public void SetOrder(SortOrder newOrder)
    4556        {
    46             order = newOrder;
     57            Order = newOrder;
    4758        }
    4859
    4960        public ListViewItemComparer()
    5061        {
    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            }
    6472            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;
    6978                    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;
    7483                    }
    7584
    7685                    if (dataType == ColumnDataType.Integer)
    7786                    {
    78                         if (int.TryParse(listViewItemX.SubItems[column].Text, out var xi) &&
    79                             int.TryParse(listViewItemY.SubItems[column].Text, out var yi))
     87                        if (int.TryParse(x.SubItems[Column].Text, out int xi) &&
     88                            int.TryParse(y.SubItems[Column].Text, out int yi))
    8089                        {
    8190                            if (xi < yi) result = -1;
     
    8695                    else if (dataType == ColumnDataType.Decimal)
    8796                    {
    88                         if (decimal.TryParse(listViewItemX.SubItems[column].Text, out var xi) &&
    89                             decimal.TryParse(listViewItemY.SubItems[column].Text, out var yi))
     97                        if (decimal.TryParse(x.SubItems[Column].Text, out decimal xi) &&
     98                            decimal.TryParse(y.SubItems[Column].Text, out decimal yi))
    9099                        {
    91100                            if (xi < yi) result = -1;
     
    96105                    else if (dataType == ColumnDataType.DateTime)
    97106                    {
    98                         if (DateTime.TryParse(listViewItemX.SubItems[column].Text, out var xi) &&
    99                             DateTime.TryParse(listViewItemY.SubItems[column].Text, out var yi))
     107                        if (DateTime.TryParse(x.SubItems[Column].Text, out DateTime xi) &&
     108                            DateTime.TryParse(y.SubItems[Column].Text, out DateTime yi))
    100109                        {
    101110                            result = DateTime.Compare(xi, yi);
     
    104113                    else if (dataType == ColumnDataType.Custom)
    105114                    {
    106                         if (OnCompareItem != null)
    107                         {
    108                             result = OnCompareItem(listViewItemX, listViewItemY, column);
     115                        if (listViewColumn?.OnCompare != null)
     116                        {
     117                            result = listViewColumn.OnCompare(x, y);
    109118                        }
    110119                    }
    111120                    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);
    114123                }
    115124                else
    116125                {
    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)
    123142            {
    124143                case SortOrder.Ascending:
     
    126145                case SortOrder.Descending:
    127146                    return -result;
     147                case SortOrder.None:
    128148                default:
    129149                    return 0;
     
    131151        }
    132152
    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);
    142373            if ((column != -1) && (order != SortOrder.None))
    143374            {
    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            }
    158423        }
    159424    }
Note: See TracChangeset for help on using the changeset viewer.