初級代碼游戲的專欄介紹與文章目錄-CSDN博客
我的github:codetoys,所有代碼都將會位于ctfc庫中。已經放入庫中我會指出在庫中的位置。
這些代碼大部分以Linux為目標但部分代碼是純C++的,可以在任何平臺上使用。
源碼指引:github源碼指引_初級代碼游戲的博客-CSDN博客
C#是我多年以來的業余愛好,新搞的東西能用C#的就用C#了。
? ? ? ? 接上一篇繼續研究排序問題。上一篇:WinUI3入門15:DataGrid排序-CSDN博客
? ? ? ? 前一篇使用OrderBy對指定列排序,如果要同時對多列排序,或許可以用一串OrderBy來實現(因為OrderBy是穩定排序,如果相等,不會改變相對順序)。
? ? ? ? 但是首先寫一串OrderBy相當繁瑣,效果存在不確定性(依賴算法特性),其次多次排序性能可能存在問題,當然這都不是關鍵問題。
????????關鍵問題是這不符合完全自定義這個目標。傳統上(指C++)我們用傳遞一個比較函數(或函數對象)的方法來實現自定義的排序規則,在C#同樣可以通過傳遞特定的接口來實現。
目錄
一、Enumerable.Order 方法
二、ICompare
三、設計通用的比較接口
一、Enumerable.Order 方法
????????ObservableCollection<>實現了IEnumerable<T> 接口,因此可以用Order方法進行排序。Order方法接受一個IComparer<T>參數:
public static System.Linq.IOrderedEnumerable<T> Order<T> (this System.Collections.Generic.IEnumerable<T> source, System.Collections.Generic.IComparer<T>? comparer);
? ? ? ? 很明顯這個ICompare<T>就是用作比較的方法,所以問題就歸結為編寫ICompare<T>。
二、ICompare<T>
????????ICompare<T>要求如下:
public int Compare (T? x, T? y);
? ? ? ? 這個我們看著很眼熟,返回值也很眼熟:0代表相等,大于0代表x>y,小于0代表x<y,跟我們傳統的x-y是一樣的。
三、設計通用的比較接口
? ? ? ? 通常為了多列比較我們需要下面的信息:
- 哪些列用作比較
- 這些列的比較順序(優先級)
- 每個列的比較方法(字符串、數值、升序降序)
? ? ? ? 因為這里是直接用屬性比較,那么字符串還是數值是不需要額外記錄的,所以要記住的就是列和升序降序,我們可以用下面的類來描述:
public class SortColumn{public String name = "";public bool sortOrderAscending = true;//false Descending}
? ? ? ? 再定義一個列表就可以描述列的順序了:
public List<SortColumn> sortColumns = new();
? ? ? ? 現在我們考慮把描述規則放在一個類里,而具體的比較由類自身的方法來實現。理論上通過上一篇用的動態類型(PropertyInfo)處理是可以實現完美的通用比較類的,不過有時候自定義一下也沒什么不好,可能更簡單、更高效。
? ? ? ? 整個通用部分如下:
public interface IMyOrder<T> where T : IMyOrder<T>{int CompareTo(MyOrder<T> order, T tmp);}public class MyOrder<T> : System.Collections.Generic.IComparer<T> where T : IMyOrder<T> {public class SortColumn{public String name = "";public bool sortOrderAscending = true;//false Descending}public List<SortColumn> sortColumns = new();public MyOrder(){}//清除排序規則public void ClearSortColumn(){sortColumns.Clear();}//指定進行排序的列public void SetSortColumn(String colname){SortColumn? sortColumn = null;int index = -1;if (sortColumns.Count != 0){for (int i = 0; i < sortColumns.Count; ++i){SortColumn tmpColumn =sortColumns[i];if (tmpColumn.name == colname){sortColumn=tmpColumn;sortColumns.Remove(tmpColumn);index = i;}}}if (null == sortColumn){sortColumn = new SortColumn();sortColumn.name = colname;sortColumns.Add(sortColumn);}else{if (0 == index) sortColumn.sortOrderAscending = !sortColumn.sortOrderAscending;sortColumns.Insert(0, sortColumn);}}public int Compare(T? x, T? y){if(null==x && null==y)return 0;if (null == x) return -1;if(null==y)return 1;return x.CompareTo(this, y);}}
? ? ? ? 前面定義了一個接口IMyOrder<T>用來由實際的數據實現比較函數。而MyOrder<T>的IComparer<T>的實現“public int Compare(T? x, T? y)”則調用IMyOrder<T>的CompareTo來實現真正的比較。
? ? ? ? 最復雜的是SetSortColumn,要檢查是否是已經存在的排序列,最新點擊的排第一,如果連續點擊第一個就改變正序逆序。
? ? ? ? 數據那邊則要增加對IMyOrder<T>的實現:
public class Data : INotifyPropertyChanged, IMyOrder<Data>{。。。。。。public int CompareTo(MyOrder<Data> order,Data tmp){for (int i = 0; i < order.sortColumns.Count; ++i){int ret = 0;MyOrder<Data>.SortColumn sortColumn = order.sortColumns[i];if (sortColumn.name == "Dir") ret = _dir.CompareTo(tmp._dir);if (sortColumn.name == "File") ret = _file.CompareTo(tmp._file);if (sortColumn.name == "Ext") ret = _ext.CompareTo(tmp._ext);if (sortColumn.name == "Type") ret = _type.CompareTo(tmp._type);if (sortColumn.name == "Encode") ret = _encode.CompareTo(tmp._encode);if (sortColumn.name == "BOM") ret = _bom.CompareTo(tmp._bom);if (sortColumn.name == "CR") ret = _cr.CompareTo(tmp._cr);if (sortColumn.name == "CRLF") ret = _crlf.CompareTo(tmp._crlf);if (sortColumn.name == "LF") ret = _lf.CompareTo(tmp._lf);if (sortColumn.name == "Length") ret = _length.CompareTo(tmp._length);if (sortColumn.name == "State") ret = _state.CompareTo(tmp._state);if (!sortColumn.sortOrderAscending) ret = -ret;if (0 != ret) return ret;}return 0;}}
? ? ? ? 主代碼中的主要過程:
MyOrder<Data> myOrder = new();//Sorting事件添加排序列myOrder.SetSortColumn(e.Column.Header.ToString());排序newdatas = datas.Order(myOrder);
(這里是文檔結束)