DataGridView使用Business Objects排序列

我正在设置我的DataGridView,如下所示:

jobs = new List(); uxJobList.AutoGenerateColumns = false; jobListBindingSource.DataSource = jobs; uxJobList.DataSource = jobListBindingSource; int newColumn; newColumn = uxJobList.Columns.Add("Id", "Job No."); uxJobList.Columns[newColumn].DataPropertyName = "Id"; uxJobList.Columns[newColumn].DefaultCellStyle.Format = Global.JobIdFormat; uxJobList.Columns[newColumn].DefaultCellStyle.Font = new Font(uxJobList.DefaultCellStyle.Font, FontStyle.Bold); uxJobList.Columns[newColumn].AutoSizeMode = DataGridViewAutoSizeColumnMode.None; uxJobList.Columns[newColumn].Width = 62; uxJobList.Columns[newColumn].Resizable = DataGridViewTriState.False; uxJobList.Columns[newColumn].SortMode = DataGridViewColumnSortMode.Automatic; : : 

DisplayJob类的外观如下:

  public class DisplayJob { public DisplayJob(int id) { Id = id; } public DisplayJob(JobEntity job) { Id = job.Id; Type = job.JobTypeDescription; CreatedAt = job.CreatedAt; StartedAt = job.StartedAt; ExternalStatus = job.ExternalStatus; FriendlyExternalStatus = job.FriendlyExternalStatus; ExternalStatusFriendly = job.ExternalStatusFriendly; CustomerName = job.Customer.Name; CustomerKey = job.Customer.CustomerKey; WorkAddress = job.WorkAddress; CreatedBy = job.CreatedBy; CancelledAt = job.CancelledAt; ClosedAt = job.ClosedAt; ReasonWaiting = job.ReasonWaiting; CancelledBy = job.CancelledBy; CancelledReason = job.CancelledReason; DisplayCreator = Global.GetDisplayName(CreatedBy); ActionRedoNeeded = job.ActionRedoNeeded; if (job.Scheme != null) { SchemeCode = job.Scheme.Code; } } public int Id { get; private set; } public string Type { get; private set; } public DateTime CreatedAt { get; private set; } public DateTime? StartedAt { get; private set; } public string ExternalStatus { get; private set; } public string FriendlyExternalStatus { get; private set; } public string ExternalStatusFriendly { get; private set; } public string CustomerName { get; private set; } public string CustomerKey { get; private set; } public string WorkAddress { get; private set; } public string CreatedBy { get; private set; } public DateTime? CancelledAt { get; private set; } public DateTime? ClosedAt { get; private set; } public string CancelledBy { get; private set; } public string ReasonWaiting { get; private set; } public string DisplayCreator { get; private set; } public string CancelledReason { get; private set; } public string SchemeCode { get; private set; } public bool ActionRedoNeeded { get; private set; } } 

但是列排序不起作用。 让这个工作的最佳方法是什么?

如果要支持对集合进行排序和搜索, 只需从BindingList参数化类型派生类 ,并覆盖一些基类方法和属性。

最好的方法是扩展BindingList并执行以下操作:

 protected override bool SupportsSearchingCore { get { return true; } } protected override bool SupportsSortingCore { get { return true; } } 

您还需要实现排序代码:

 ListSortDirection sortDirectionValue; PropertyDescriptor sortPropertyValue; protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { sortedList = new ArrayList(); // Check to see if the property type we are sorting by implements // the IComparable interface. Type interfaceType = prop.PropertyType.GetInterface("IComparable"); if (interfaceType != null) { // If so, set the SortPropertyValue and SortDirectionValue. sortPropertyValue = prop; sortDirectionValue = direction; unsortedItems = new ArrayList(this.Count); // Loop through each item, adding it the the sortedItems ArrayList. foreach (Object item in this.Items) { sortedList.Add(prop.GetValue(item)); unsortedItems.Add(item); } // Call Sort on the ArrayList. sortedList.Sort(); T temp; // Check the sort direction and then copy the sorted items // back into the list. if (direction == ListSortDirection.Descending) sortedList.Reverse(); for (int i = 0; i < this.Count; i++) { int position = Find(prop.Name, sortedList[i]); if (position != i) { temp = this[i]; this[i] = this[position]; this[position] = temp; } } isSortedValue = true; // Raise the ListChanged event so bound controls refresh their // values. OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } else // If the property type does not implement IComparable, let the user // know. throw new NotSupportedException("Cannot sort by " + prop.Name + ". This" + prop.PropertyType.ToString() + " does not implement IComparable"); } 

如果您需要更多信息,可以随时访问并获取有关如何扩展绑定列表的所有说明。

Daok的解决方案是正确的。 它的工作量往往超过它的价值。

懒人获得所需function的方法是从业务对象创建并填充DataTable,并将DataGridView绑定到该对象。

这种方法有很多用例无法处理(比如编辑),显然会浪费时间和空间。 正如我所说,这是懒惰的。

但它很容易编写,并且生成的代码比IBindingList的实现更神秘。

此外,你已经编写了很多代码,或者至少编写了类似的代码:你编写的用于定义DataTable的代码使你不必编写代码来创建DataGridView的列,因为DataGridView将构造它的列绑定时关闭DataTable。

最简单的方法之一是使用BindingListView类来包装DisplayJobs列表。 该类实现了一些必需的接口,可以在DataGridView中进行排序和过滤。 这是快捷的方式。 但是它运行得很好 – 唯一需要注意的是,如果你从DataGridView中抛出东西,你需要转换为包装器对象(ObjectView)而不是实际的项目(DisplayJob)。

不太懒惰的方法是创建实现IBindingList的自定义集合时间,在那里实现排序方法。

Daok建议的MS文章让我走上正轨,但我对MS的SortableSearchableList实现不满意。 我发现该实现非常奇怪,并且当列中存在重复值时它无法正常工作。 它也不会覆盖IsGortedCore,这似乎是DataGridView所需要的。 如果未覆盖IsSortedCore,则不会显示搜索字形,并且在升序和降序之间切换不起作用。

请参阅下面的我的SortableSearchableList版本。 在ApplySortCore()中,它使用比较委托集对匿名方法进行排序。 此版本还支持为特定属性设置自定义比较,可以使用AddCustomCompare()由派生类添加。

我不确定版权声明是否仍适用,但我只是将其保留了下来。

 //--------------------------------------------------------------------- // Copyright (C) Microsoft Corporation. All rights reserved. // //THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY //KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE //IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A //PARTICULAR PURPOSE. //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Reflection; using System.Collections; namespace SomethingSomething { ///  /// Supports sorting of list in data grid view. ///  /// Type of object to be displayed in data grid view. public class SortableSearchableList : BindingList { #region Data Members private ListSortDirection _sortDirectionValue; private PropertyDescriptor _sortPropertyValue = null; ///  /// Dictionary from property name to custom comparison function. ///  private Dictionary> _customComparisons = new Dictionary>(); #endregion #region Constructors ///  /// Default constructor. ///  public SortableSearchableList() { } #endregion #region Properties ///  /// Indicates if sorting is supported. ///  protected override bool SupportsSortingCore { get { return true; } } ///  /// Indicates if list is sorted. ///  protected override bool IsSortedCore { get { return _sortPropertyValue != null; } } ///  /// Indicates which property the list is sorted. ///  protected override PropertyDescriptor SortPropertyCore { get { return _sortPropertyValue; } } ///  /// Indicates in which direction the list is sorted on. ///  protected override ListSortDirection SortDirectionCore { get { return _sortDirectionValue; } } #endregion #region Methods ///  /// Add custom compare method for property. ///  ///  ///  protected void AddCustomCompare(string propertyName, Comparison comparison) { _customComparisons.Add(propertyName, comparison); } ///  /// Apply sort. ///  ///  ///  protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { Comparison comparison; if (!_customComparisons.TryGetValue(prop.Name, out comparison)) { // Check to see if the property type we are sorting by implements // the IComparable interface. Type interfaceType = prop.PropertyType.GetInterface("IComparable"); if (interfaceType != null) { comparison = delegate(T t1, T t2) { IComparable val1 = (IComparable)prop.GetValue(t1); IComparable val2 = (IComparable)prop.GetValue(t2); return val1.CompareTo(val2); }; } else { // Last option: convert to string and compare. comparison = delegate(T t1, T t2) { string val1 = prop.GetValue(t1).ToString(); string val2 = prop.GetValue(t2).ToString(); return val1.CompareTo(val2); }; } } if (comparison != null) { // If so, set the SortPropertyValue and SortDirectionValue. _sortPropertyValue = prop; _sortDirectionValue = direction; // Create sorted list. List _sortedList = new List(this); _sortedList.Sort(comparison); // Reverse order if needed. if (direction == ListSortDirection.Descending) { _sortedList.Reverse(); } // Update list. int count = this.Count; for (int i = 0; i < count; i++) { this[i] = _sortedList[i]; } // Raise the ListChanged event so bound controls refresh their // values. OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } } // Method below was in the original implementation from MS. Don't know what it's for. // -- Martijn Boeker, Jan 21, 2010 //protected override void RemoveSortCore() //{ // //int position; // //object temp; // //// Ensure the list has been sorted. // //if (unsortedItems != null) // //{ // // // Loop through the unsorted items and reorder the // // // list per the unsorted list. // // for (int i = 0; i < unsortedItems.Count; ) // // { // // position = this.Find(SortPropertyCore.Name, // // unsortedItems[i].GetType(). // // GetProperty(SortPropertyCore.Name). // // GetValue(unsortedItems[i], null)); // // if (position >= 0 && position != i) // // { // // temp = this[i]; // // this[i] = this[position]; // // this[position] = (T)temp; // // i++; // // } // // else if (position == i) // // i++; // // else // // // If an item in the unsorted list no longer exists, delete it. // // unsortedItems.RemoveAt(i); // // } // // OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); // //} //} ///  /// Ability to search an item. ///  protected override bool SupportsSearchingCore { get { return true; } } ///  /// Finds an item in the list. ///  ///  ///  ///  protected override int FindCore(PropertyDescriptor prop, object key) { // Implementation not changed from MS example code. // Get the property info for the specified property. PropertyInfo propInfo = typeof(T).GetProperty(prop.Name); T item; if (key != null) { // Loop through the the items to see if the key // value matches the property value. for (int i = 0; i < Count; ++i) { item = (T)Items[i]; if (propInfo.GetValue(item, null).Equals(key)) return i; } } return -1; } ///  /// Finds an item in the list. ///  ///  ///  ///  private int Find(string property, object key) { // Implementation not changed from MS example code. // Check the properties for a property with the specified name. PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); PropertyDescriptor prop = properties.Find(property, true); // If there is not a match, return -1 otherwise pass search to // FindCore method. if (prop == null) return -1; else return FindCore(prop, key); } #endregion } } 

我相信你的类必须实现IComparable接口。

希望能帮助到你,

布鲁诺菲格雷多

我建议更换:

 jobs = new List(); 

有:

 jobs = new SortableBindingList(); 

SortableBindingList的代码在这里: http : //www.timvw.be/presenting-the-sortablebindinglistt/

我在生产中使用了基于此的代码而没有任何问题。 唯一的限制是它不是一种稳定的排序。

如果您希望排序稳定,请替换:

 itemsList.Sort(delegate(T t1, T t2) { object value1 = prop.GetValue(t1); object value2 = prop.GetValue(t2); return reverse * Comparer.Default.Compare(value1, value2); }); 

插入排序:

 int j; T index; for (int i = 0; i < itemsList.Count; i++) { index = itemsList[i]; j = i; while ((j > 0) && (reverse * Comparer.Default.Compare(prop.GetValue(itemsList[j - 1]), prop.GetValue(index)) > 0)) { itemsList[j] = itemsList[j - 1]; j = j - 1; } itemsList[j] = index; } 

Martijn优秀的代码,但只有一个细节你需要validation空单元格或空:)

 if (!_customComparisons.TryGetValue(prop.Name, out comparison)) { // Check to see if the property type we are sorting by implements // the IComparable interface. Type interfaceType = prop.PropertyType.GetInterface("IComparable"); if (interfaceType != null) { comparison = delegate(T t1, T t2) { IComparable val1 = (IComparable)prop.GetValue(t1) ?? ""; IComparable val2 = (IComparable)prop.GetValue(t2) ?? ""; return val1.CompareTo(val2); }; } else { // Last option: convert to string and compare. comparison = delegate(T t1, T t2) { string val1 = (prop.GetValue(t1) ?? "").ToString(); string val2 = (prop.GetValue(t2) ?? "").ToString(); return val1.CompareTo(val2); }; } } 

那都好运

您是否尝试为每列设置SortMemberPath?

uxJobList.Columns[newColumn].SortMemberPath="Id";

而不是List我只是使用ObservableCollection