2008-11-11 49 views
5

tôi đang thiết lập DataGridView của tôi như thế này:DataGridView cột sắp xếp với Business Objects

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

nơi lớp DisplayJob trông giống như:

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

Tuy nhiên, phân loại cột không hoạt động. Cách tốt nhất để làm việc này là gì?

Trả lời

9

Nếu bạn muốn hỗ trợ sắp xếp và tìm kiếm trên bộ sưu tập, tất cả phải mất nó để lấy được một lớp từ loại BindingList tham số và ghi đè lên một vài phương thức và thuộc tính cơ sở.

Cách tốt nhất là để mở rộng BindingList và làm những điều sau đây:

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

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

Bạn cũng sẽ cần phải thực hiện các mã loại:

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

Nếu bạn cần biết thêm thông tin bạn có thể luôn đến đó và nhận được tất cả các giải thích về how to extend the binding list.

1

Tôi tin rằng lớp học của bạn phải triển khai giao diện IComparable.

Hy vọng nó giúp,

Bruno Figueiredo

3

Một trong những cách đơn giản nhất là sử dụng lớp BindingListView quấn danh sách các DisplayJobs. Lớp thực hiện một số giao diện cần thiết cho phép sắp xếp và lọc trong một DataGridView. Đó là cách nhanh chóng. Nó hoạt động khá tốt, mặc dù - chỉ báo trước là nếu bạn cast những thứ ra khỏi DataGridView bạn cần phải cast cho đối tượng wrapper (ObjectView) thay vì mục thực tế (DisplayJob).

Cách ít tốn kém hơn là tạo thời gian thu thập tùy chỉnh triển khai IBindingList, triển khai phương pháp sắp xếp ở đó.

+0

BindingListView thuận tiện có sẵn thông qua NuGet: Cài đặt-Package Unofficial.BindingListView – user1016736

5

Giải pháp của Daok là giải pháp phù hợp. Nó cũng thường làm việc nhiều hơn nó có giá trị.

Cách của người lười biếng để có được chức năng bạn muốn là tạo và điền một DataTable ra khỏi các đối tượng kinh doanh của bạn và ràng buộc DataGridView với điều đó.

Có rất nhiều trường hợp sử dụng mà cách tiếp cận này sẽ không xử lý (như, chỉnh sửa) và rõ ràng là lãng phí thời gian và không gian. Như tôi đã nói, nó lười.

Nhưng thật dễ dàng để viết và mã kết quả là một cảnh chết tiệt ít bí ẩn hơn việc triển khai IBindingList.

Ngoài ra, bạn đã viết rất nhiều mã, hoặc mã tương tự ít nhất: mã bạn viết để xác định DataTable giải phóng bạn khỏi phải viết mã để tạo các cột của DataGridView, vì DataGridView sẽ xây dựng các cột của nó ra khỏi DataTable khi bạn liên kết nó.

3

Bài viết MS do Daok đề xuất giúp tôi đi đúng hướng, nhưng tôi không hài lòng với việc triển khai SortableSearchableList của MS. Tôi thấy rằng việc thực hiện rất lạ và nó không hoạt động tốt khi có các giá trị trùng lặp trong một cột.Nó cũng không ghi đè IsSortedCore, mà dường như được yêu cầu bởi DataGridView. Nếu IsSortedCore không được overriden, glyph tìm kiếm không xuất hiện và toggling giữa tăng dần và giảm dần không hoạt động.

Xem phiên bản SortableSearchableList của tôi bên dưới. Trong ApplySortCore() nó sắp xếp bằng cách sử dụng một delegate Compare được đặt thành một phương thức nặc danh. Phiên bản này cũng hỗ trợ thiết lập các so sánh tùy chỉnh cho một thuộc tính cụ thể, có thể được thêm vào bởi một lớp dẫn xuất sử dụng AddCustomCompare().

Tôi không chắc chắn nếu thông báo bản quyền vẫn được áp dụng, nhưng tôi vừa mới rời khỏi nó trong.

//--------------------------------------------------------------------- 
// 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

Giải pháp này hoạt động tốt, cảm ơn bạn – Drake

+0

1 cho người cuối cùng đặt trong các không gian tên chúng bao gồm. – SteveCav

0

Martijn đang xuất sắc nhưng chỉ có một chi tiết u cần phải xác nhận tế bào null hoặc rỗng :)

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

Đó là tất cả may mắn

1

tôi khuyên bạn nên thay thế:

jobs = new List<DisplayJob>(); 

với:

jobs = new SortableBindingList<DisplayJob>(); 

Mã cho SortableBindingList là ở đây: http://www.timvw.be/presenting-the-sortablebindinglistt/

Tôi đã sử dụng mã dựa trên này trong sản xuất mà không cần bất kỳ vấn đề. Đó là hạn chế duy nhất là nó không phải là một loại ổn định.

Nếu bạn muốn sắp xếp để được ổn định, thay thế:

itemsList.Sort(delegate(T t1, T t2) 
{ 
    object value1 = prop.GetValue(t1); 
    object value2 = prop.GetValue(t2); 

    return reverse * Comparer.Default.Compare(value1, value2); 
}); 

với một loại chèn:

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

Bạn có cố gắng thiết lập SortMemberPath cho mỗi cột?

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

và thay vì Danh sách im chỉ sử dụng ObservableCollection

Các vấn đề liên quan