2008-11-11 39 views
5

我的建立我的DataGridView這樣的:DataGridView的列與業務排序對象

 jobs = new List<DisplayJob>(); 

     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; } 
} 

然而,列排序不起作用。什麼是最好的方式來得到這個工作?

回答

9

如果你想支持排序和搜索集合,所有它需要它從你的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"); 
} 

去那裏,得到關於how to extend the binding list的所有說明。

1

我相信你的班級必須實現IComparable接口。

希望它能幫助,

布魯諾·菲格雷多

3

一個最簡單的方法是使用BindingListView類來包裝你的DisplayJobs的列表。該類實現了一些必需的接口,可以在DataGridView中進行排序和過濾。這是快速的方法。它工作得很好 - 唯一的警告是,如果你把東西扔出DataGridView,你需要將其轉換爲包裝對象(ObjectView)而不是實際的項目(DisplayJob)。

不那麼懶惰的方法是創建一個實現IBindingList的自定義收集時間,在那裏實現排序方法。

+0

BindingListView是方便可行的通過的NuGet:安裝,包裝Unofficial.BindingListView – user1016736 2014-02-14 17:01:24

5

Daok的解決方案是正確的。這也往往是更多的工作,而不是價值。

懶人的方式來獲得您想要的功能是創建和填充DataTable的業務對象,並綁定到DataGridView。

這種方法無法處理很多用例(如編輯),顯然浪費時間和空間。正如我所說,這很懶惰。

但它很容易編寫,並且由此產生的代碼是一個比IBindingList的實現更神祕的視覺。

此外,您至少已經編寫了很多代碼或至少類似的代碼:您編寫的用於定義DataTable的代碼使您無需編寫代碼來創建DataGridView的列,因爲DataGridView在綁定它時將從DataTable構建它的列。

3

Daok建議的MS文章讓我走上了正軌,但我並不滿意於SortableSearListList的MS實現。我發現這個實現非常奇怪,並且在列中有重複值時效果不佳。它也不會覆蓋IsSortedCore,這似乎是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 
{ 
    /// <summary> 
    /// Supports sorting of list in data grid view. 
    /// </summary> 
    /// <typeparam name="T">Type of object to be displayed in data grid view.</typeparam> 
    public class SortableSearchableList<T> : BindingList<T> 
    { 
     #region Data Members 

     private ListSortDirection _sortDirectionValue; 
     private PropertyDescriptor _sortPropertyValue = null; 

     /// <summary> 
     /// Dictionary from property name to custom comparison function. 
     /// </summary> 
     private Dictionary<string, Comparison<T>> _customComparisons = new Dictionary<string, Comparison<T>>(); 

     #endregion 

     #region Constructors 

     /// <summary> 
     /// Default constructor. 
     /// </summary> 
     public SortableSearchableList() 
     { 
     } 

     #endregion 

     #region Properties 

     /// <summary> 
     /// Indicates if sorting is supported. 
     /// </summary> 
     protected override bool SupportsSortingCore 
     { 
      get 
      { 
       return true; 
      } 
     } 

     /// <summary> 
     /// Indicates if list is sorted. 
     /// </summary> 
     protected override bool IsSortedCore 
     { 
      get 
      { 
       return _sortPropertyValue != null; 
      } 
     } 

     /// <summary> 
     /// Indicates which property the list is sorted. 
     /// </summary> 
     protected override PropertyDescriptor SortPropertyCore 
     { 
      get 
      { 
       return _sortPropertyValue; 
      } 
     } 

     /// <summary> 
     /// Indicates in which direction the list is sorted on. 
     /// </summary> 
     protected override ListSortDirection SortDirectionCore 
     { 
      get 
      { 
       return _sortDirectionValue; 
      } 
     } 

     #endregion 

     #region Methods  

     /// <summary> 
     /// Add custom compare method for property. 
     /// </summary> 
     /// <param name="propertyName"></param> 
     /// <param name="compareProperty"></param> 
     protected void AddCustomCompare(string propertyName, Comparison<T> comparison) 
     { 
      _customComparisons.Add(propertyName, comparison); 
     } 

     /// <summary> 
     /// Apply sort. 
     /// </summary> 
     /// <param name="prop"></param> 
     /// <param name="direction"></param> 
     protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) 
     { 
      Comparison<T> 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<T> _sortedList = new List<T>(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)); 
     // //} 
     //} 

     /// <summary> 
     /// Ability to search an item. 
     /// </summary> 
     protected override bool SupportsSearchingCore 
     { 
      get 
      { 
       return true; 
      } 
     } 

     /// <summary> 
     /// Finds an item in the list. 
     /// </summary> 
     /// <param name="prop"></param> 
     /// <param name="key"></param> 
     /// <returns></returns> 
     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; 
     } 

     /// <summary> 
     /// Finds an item in the list. 
     /// </summary> 
     /// <param name="prop"></param> 
     /// <param name="key"></param> 
     /// <returns></returns> 
     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 
    } 
} 
+0

這個解決方案工作得很好,謝謝你 – Drake 2010-10-05 15:33:33

0

的Martijn外觀極好的代碼,但只有一個細節u需要驗證空細胞或空:)

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); 
      }; 
    } 
} 

這就是運氣

1

我會建議更換:

jobs = new List<DisplayJob>(); 

有:

jobs = new SortableBindingList<DisplayJob>(); 

爲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; 
} 
0

你有沒有嘗試設置SortMemberPath每列?

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

和而不是List我只是使用的ObservableCollection