C # — проблемы с сортировкой datagridview

#c# #list #sorting #datagridview

#c# #Список #сортировка #datagridview

Вопрос:

Я изо всех сил искал ответ на свою проблему. Я разработал программу Winforms на c # с несколькими datagridviews.

Проблема в том, что я хочу, чтобы пользователь мог сортировать datagridview, нажав на заголовок столбца (я думал, это будет стандартным …) Но это просто не работает.

Я попробовал метод dgv.Sort, но это выдает исключение, что datagridview должен быть привязан к IBindingList, но я понятия не имею, как это сделать, и я действительно не хочу все переделывать..

Вот как я заполняю свой dgv.

У меня есть определенные пользовательские объекты, и я помещаю их в список. Когда этот список полностью заполнен, я устанавливаю его в качестве источника данных для dgv.

 list.Add(costumobject);
.
.
.
dgv.DataSource = list;
 

Не могли бы вы, пожалуйста, подсказать мне быстрый способ заставить функцию сортировки работать?

С уважением,

Комментарии:

1. Нажмите кнопку сортировки -> Отсортировать список -> поместить источник данных -> Повторно привязать сетку

2. Вы решили свои проблемы?

Ответ №1:

DataGridView не выполняет внутреннюю сортировку своих строк самостоятельно. Вместо этого он использует функциональность сортировки подключенного источника данных, и если источник данных не предоставляет функции сортировки, сортировка столбцов DataGridView также недоступна.

Создайте SortableBindingList и используйте его вместо списка.

 using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace YourNamespace
{
    /// <summary>
    /// Provides a generic collection that supports data binding and additionally supports sorting.
    /// See http://msdn.microsoft.com/en-us/library/ms993236.aspx
    /// If the elements are IComparable it uses that; otherwise compares the ToString()
    /// </summary>
    /// <typeparam name="T">The type of elements in the list.</typeparam>
    public class SortableBindingList<T> : BindingList<T> where T : class
    {
        private bool _isSorted;
        private ListSortDirection _sortDirection = ListSortDirection.Ascending;
        private PropertyDescriptor _sortProperty;

        /// <summary>
        /// Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
        /// </summary>
        public SortableBindingList()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
        /// </summary>
        /// <param name="list">An <see cref="T:System.Collections.Generic.IList`1" /> of items to be contained in the <see cref="T:System.ComponentModel.BindingList`1" />.</param>
        public SortableBindingList(IList<T> list) : base(list)
        {
        }

        /// <summary>
        /// Gets a value indicating whether the list supports sorting.
        /// </summary>
        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

        /// <summary>
        /// Gets a value indicating whether the list is sorted.
        /// </summary>
        protected override bool IsSortedCore
        {
            get { return _isSorted; }
        }

        /// <summary>
        /// Gets the direction the list is sorted.
        /// </summary>
        protected override ListSortDirection SortDirectionCore
        {
            get { return _sortDirection; }
        }

        /// <summary>
        /// Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class; otherwise, returns null
        /// </summary>
        protected override PropertyDescriptor SortPropertyCore
        {
            get { return _sortProperty; }
        }

        /// <summary>
        /// Removes any sort applied with ApplySortCore if sorting is implemented
        /// </summary>
        protected override void RemoveSortCore()
        {
            _sortDirection = ListSortDirection.Ascending;
            _sortProperty = null;
            _isSorted = false; //thanks Luca
        }

        /// <summary>
        /// Sorts the items if overridden in a derived class
        /// </summary>
        /// <param name="prop"></param>
        /// <param name="direction"></param>
        protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
        {
            _sortProperty = prop;
            _sortDirection = direction;

            List<T> list = Items as List<T>;
            if (list == null) return;
            list.Sort(Compare);
            _isSorted = true;
            //fire an event that the list has been changed.
            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        private int Compare(T lhs, T rhs)
        {
            var result = OnComparison(lhs, rhs);
            //invert if descending
            if (_sortDirection == ListSortDirection.Descending)
                result = -resu<
            return resu<
        }

        private int OnComparison(T lhs, T rhs)
        {
            object lhsValue = lhs == null ? null : _sortProperty.GetValue(lhs);
            object rhsValue = rhs == null ? null : _sortProperty.GetValue(rhs);
            if (lhsValue == null)
            {
                return (rhsValue == null) ? 0 : -1; //nulls are equal
            }

            if (rhsValue == null)
            {
                return 1; //first has value, second doesn't
            }

            if (lhsValue is IComparable)
            {
                return ((IComparable)lhsValue).CompareTo(rhsValue);
            }

            if (lhsValue.Equals(rhsValue))
            {
                return 0; //both are the same
            }

            //not comparable, compare ToString
            return lhsValue.ToString().CompareTo(rhsValue.ToString());
        }
    }
}
 

Ответ №2:

List<T> не поддерживает сортировку напрямую.

Вместо этого вы можете использовать процедуру Linq для выполнения сортировки.

Однако вам нужно будет включить проверку поля сортировки, которая будет соответствовать вашему количеству столбцов..

Не зная вашего customobject класса, давайте попробуем с Name классом:

 class Name
{
    public string first { get; set; }
    public string last { get; set; }
    public string middle { get; set; }

    public Name (string f, string m, string l)
    {
        first = f; middle = m; last = l;
    }
}
 

Теперь давайте закодируем ColumnHeaderMouseClick событие:

 private void dataGridView1_ColumnHeaderMouseClick(object sender, 
                           DataGridViewCellMouseEventArgs e)
{
    List<Name> names = dataGridView1.DataSource as List<Name>;
    string col = dataGridView2.Columns[e.ColumnIndex].DataPropertyName;
    string order =  " ASC";
    if (dataGridView1.Tag != null) 
        order = dataGridView1.Tag.ToString().Contains(" ASC") ? " DESC" : " ASC";

    dataGridView1.Tag = col   order;

    if (order.Contains(" ASC"))
    names = names.OrderBy(x => col == "first"? x.first 
                             : col == "last" ? x.last : x.middle).ToList();  
    else
    names = names.OrderByDescending(x => col == "first"? x.first : 
                                         col == "last" ? x.last : x.middle).ToList();  

    dataGridView1.DataSource = names;
}
 

Обратите внимание, что я сохраняю текущий столбец сортировки и порядок в DGV Tag . Вы можете переместить его в переменную уровня класса или в какое-либо другое место. К сожалению SortOrder , свойство DGV не может быть установлено..

Ответ №3:

вы пытались обновить datagrid после изменения источника данных?

 list.Add(costumobject);
.
.
.
dgv.DataSource = list;
dgv.Refresh();