5

我正在像这样设置我的 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; }
}

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

4

8 回答 8

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

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

于 2008-11-11T14:17:50.990 回答
5

Daok 的解决方案是正确的。它也经常比它的价值更多的工作。

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

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

但它很容易编写,并且生成的代码比IBindingList.

此外,无论如何,您已经编写了很多代码,或者至少是类似的代码:您编写定义 DataTable 的代码使您不必编写代码来创建 DataGridView 的列,因为 DataGridView 将构建它的列绑定数据表时关闭它。

于 2008-11-11T19:57:50.460 回答
3

最简单的方法之一是使用BindingListView类来包装您的 DisplayJobs 列表。该类实现了一些在 DataGridView 中启用排序和筛选所需的接口。那是快速的方法。不过,它工作得很好——唯一需要注意的是,如果你从 DataGridView 中投射东西,你需要投射到包装对象 (ObjectView) 而不是实际项目 (DisplayJob)。

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

于 2008-11-11T14:07:38.543 回答
3

Daok 建议的 MS 文章让我走上了正轨,但我对 MS 的 SortableSearchableList 实现并不满意。我发现这个实现很奇怪,当列中有重复值时它不能很好地工作。它也不会覆盖 DataGridView 似乎需要的 IsSortedCore。如果 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
    }
}
于 2010-01-22T07:30:32.943 回答
1

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

希望能帮助到你,

布鲁诺·菲格雷多

于 2008-11-11T14:04:49.797 回答
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;
}
于 2010-01-26T05:42:04.977 回答
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);
            };
    }
}

这都是运气

于 2010-01-26T01:03:18.187 回答
0

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

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

而不是 List im 只是使用 ObservableCollection

于 2011-04-14T11:39:36.470 回答