C# 使用业务对象对DataGridView列进行排序

C# 使用业务对象对DataGridView列进行排序,c#,.net,datagridview,C#,.net,Datagridview,我正在设置DataGridView,如下所示: jobs = new List<DisplayJob>(); uxJobList.AutoGenerateColumns = false; jobListBindingSource.DataSource = jobs; uxJobList.DataSource = jobListBindingSource; int newColumn;

我正在设置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;
        :
        :

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

我认为您的类必须实现
IComparable
接口

希望有帮助


Bruno Figueiredo

最简单的方法之一是使用该类包装显示作业列表。该类实现了一些必需的接口,这些接口支持在DataGridView中进行排序和筛选。这是捷径。不过,它工作得很好——唯一需要注意的是,如果从DataGridView中强制转换内容,则需要转换到包装器对象(ObjectView),而不是实际的项(DisplayJob)


不那么懒惰的方法是创建一个实现IBindingList的自定义集合时间,在其中实现排序方法。

如果您想支持对集合进行排序和搜索,则需要从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");
}
ListSortDirection-sortdirection-value;
PropertyDescriptor sortPropertyValue;
受保护的覆盖无效ApplySortCore(PropertyDescriptor属性,
ListSortDirection(方向)
{
sortedList=新的ArrayList();
//检查我们正在按实现排序的属性类型
//IComparable接口。
类型interfaceType=prop.PropertyType.GetInterface(“IComparable”);
if(interfaceType!=null)
{
//如果是,请设置SortPropertyValue和SortDirectionValue。
sortPropertyValue=prop;
sortDirectionValue=方向;
unsortedItems=新的ArrayList(this.Count);
//循环遍历每个项目,将其添加到sortedItems ArrayList中。
foreach(此.Items中的对象项){
sortedList.Add(属性GetValue(项目));
未分类。添加(项);
}
//在ArrayList上调用Sort。
sortedList.Sort();
温度;
//检查排序方向,然后复制已排序的项目
//回到名单上。
if(方向==ListSortDirection.Descending)
sortedList.Reverse();
for(int i=0;i

如果你需要更多的信息,你可以随时去那里得到所有的解释。

Daok的解决方案是正确的。这也常常是超出其价值的工作

懒人获得所需功能的方法是从业务对象中创建和填充一个DataTable,并将DataGridView绑定到该DataTable

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

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


另外,您已经编写了很多代码,或者至少编写了类似的代码:您为定义DataTable而编写的代码使您无需编写代码来创建DataGridView的列,因为绑定DataGridView时,DataGridView将在DataTable之外构造其列。

Daok建议的MS文章让我走上了正确的轨道,但我对SortableSearchableList的MSs实现不满意。我发现这个实现非常奇怪,当一列中有重复的值时,它不能很好地工作。它也不会覆盖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
    }
}
//---------------------------------------------------------------------
//版权所有(C)微软公司。版权所有。
// 
//本规范和信息按原样提供,不提供任何担保
//明示或暗示的种类,包括但不限于
//对产品适销性和/或适用性的默示保证
//特殊目的。
//---------------------------------------------------------------------
使用制度;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用系统文本;
使用System.Windows.Forms;
运用系统反思;
使用系统集合;
名称空间某物某物
{
/// 
///支持在数据网格视图中对列表进行排序。
/// 
///要在数据网格视图中显示的对象类型。
公共类SortableSearchableList:BindingList
{
#区域数据成员
私有ListSortDirection\u sortDirectionValue;
私有属性描述符_sortPropertyValue=null;
/// 
///从属性名到自定义比较函数的字典。
/// 
私人词典
//---------------------------------------------------------------------
//  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
    }
}
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);
            };
    }
}
jobs = new List<DisplayJob>();
jobs = new SortableBindingList<DisplayJob>();
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;
}