我正在设置我的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; }
}
然而,列排序不起作用。让这个工作的最佳方法是什么?
答案 0 :(得分: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 :(得分:5)
Daok的解决方案是正确的。它的工作量往往超过它的价值。
懒人获得所需功能的方法是从业务对象创建并填充DataTable,并将DataGridView绑定到该对象。
这种方法有很多用例无法处理(比如编辑),显然会浪费时间和空间。正如我所说,这是懒惰的。
但它很容易编写,而且生成的代码比IBindingList
的实现更神秘。
另外,你已经编写了很多代码,或者至少编写了类似的代码:你编写的用于定义DataTable的代码使你无需编写代码来创建DataGridView的列,因为DataGridView将会在绑定它时,从DataTable构造其列。
答案 2 :(得分:3)
最简单的方法之一是使用BindingListView类来包装DisplayJobs列表。该类实现了一些必需的接口,可以在DataGridView中进行排序和过滤。这是快速的方式。但是它运行得很好 - 唯一需要注意的是,如果你从DataGridView中抛出东西,你需要转换为包装器对象(ObjectView)而不是实际的项目(DisplayJob)。
不太懒惰的方法是创建一个实现IBindingList的自定义集合时间,在那里实现排序方法。
答案 3 :(得分:3)
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
{
/// <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
}
}
答案 4 :(得分:1)
我相信您的班级必须实施IComparable
界面。
希望它有所帮助,
Bruno Figueiredo
答案 5 :(得分: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;
}
答案 6 :(得分:0)
Martijn优秀代码,但只有一个细节需要验证空单元格或空白:)
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);
};
}
}
这一切都好运
答案 7 :(得分:0)
您是否尝试为每列设置SortMemberPath?
uxJobList.Columns[newColumn].SortMemberPath="Id";
而不是List我只使用ObservableCollection