WinForms: просмотр сетки данных — программная сортировка

#c# #winforms #data-binding #sorting #datagridview

#c# #winforms #привязка данных #сортировка #datagridview

Вопрос:

У меня есть форма с datagridview на ней. DataGridView привязан к BindingSource:

 public class Address
{
    public string State { get; set; }
    public string City { get; set; }
    public string Street { get; set; }
}
this.addressBindingSource.DataSource = typeof(Address);
this.dataGridView1.DataSource = this.addressBindingSource;
  

Я заполняю DataSource вот так:

     addressBindingSource.DataSource = new BindingList<Address>
    {
        new Address {State = "S1", City = "C1", Street = "S1"},
        new Address {State = "S1", City = "C1", Street = "S2"},
        new Address {State = "S1", City = "C1", Street = "S3"},
        new Address {State = "S1", City = "C2", Street = "S4"},
        new Address {State = "S1", City = "C2", Street = "S5"},
        new Address {State = "S1", City = "C2", Street = "S6"},
    };
  

Я пытаюсь включить сортировку для этого datagridview. Я установил SortMode значение Programmatic для всех столбцов dataGridView1. И я добавил обработчик событий для ColumnHeaderMouseClick :

     private Dictionary<int, string> columnIndexPropertyNameDictionary = new Dictionary<int, string>
        {
            {0, "State"},
            {1, "City"},
            {2, "Street"},
        };

private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex < 0)
        return;

    for (int i = 0; i < dataGridView1.Columns.Count; i  )
    {
        if (i == e.ColumnIndex)
            continue;
        dataGridView1.Columns[i].HeaderCell.SortGlyphDirection = SortOrder.None;
    }

    var column = dataGridView1.Columns[e.ColumnIndex];

    if (column.SortMode != DataGridViewColumnSortMode.Programmatic)
        return;

    var sortGlyphDirection = column.HeaderCell.SortGlyphDirection;

    switch (sortGlyphDirection)
    {
        case SortOrder.None:
        case SortOrder.Ascending:
            addressBindingSource.Sort = columnIndexPropertyNameDictionary[e.ColumnIndex]   " ASC";
            column.HeaderCell.SortGlyphDirection = SortOrder.Descending;
            break;
        case SortOrder.Descending:
            addressBindingSource.Sort = columnIndexPropertyNameDictionary[e.ColumnIndex]   " DESC";
            column.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
            break;
    }
}
  

Сортировка по-прежнему не работает. Что я делаю не так?

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

1. Я заметил это addressBindingSource.SupportsSorting = false . Почему это?

Ответ №1:

Проблема в том, что готовый список привязок не поддерживает сортировку! Я знаю — звучит глупо, но так оно и есть.

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

Этот код взят отсюда, и у меня нет времени его тщательно проверять. Если это не работает, тогда найдите в Google термин SortableBindingList, существует множество реализаций.

 public class SortableBindingList<t> : BindingList<t>
{
    private bool m_Sorted = false;
    private ListSortDirection m_SortDirection = ListSortDirection.Ascending;
    private PropertyDescriptor m_SortProperty = null;

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

    protected override bool IsSortedCore
    {
        get
        {
            return m_Sorted;
        }
    }

    protected override ListSortDirection SortDirectionCore
    {
        get
        {
            return m_SortDirection;
        }
    }

    protected override PropertyDescriptor SortPropertyCore
    {
        get
        {
            return m_SortProperty;
        }
    }

    protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
    {
        m_SortDirection = direction;
        m_SortProperty = prop;
        var listRef = this.Items as List<t>;
        if (listRef == null)
            return;
        var comparer = new SortComparer<t>(prop, direction);

        listRef.Sort(comparer);

        OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
   }
}
  

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

1. 1 для SortableBindingList. Наконец, я иду в направлении сортировки.

Ответ №2:

Я использую эту простую функцию при добавлении новой строки:

 dataGridViewResult.Sort(dataGridViewResult.Columns[0], ListSortDirection.Descending);
  

Ответ №3:

 private void sortButton_Click(object sender, System.EventArgs e)
{
    // Check which column is selected, otherwise set NewColumn to null.
    DataGridViewColumn newColumn =
        dataGridView1.Columns.GetColumnCount(
        DataGridViewElementStates.Selected) == 1 ?
        dataGridView1.SelectedColumns[0] : null;

    DataGridViewColumn oldColumn = dataGridView1.SortedColumn;
    ListSortDirection direction;

    // If oldColumn is null, then the DataGridView is not currently sorted.
    if (oldColumn != null)
    {
        // Sort the same column again, reversing the SortOrder.
        if (oldColumn == newColumn amp;amp;
            dataGridView1.SortOrder == SortOrder.Ascending)
        {
            direction = ListSortDirection.Descending;
        }
        else
        {
            // Sort a new column and remove the old SortGlyph.
            direction = ListSortDirection.Ascending;
            oldColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
        }
    }
    else
    {
        direction = ListSortDirection.Ascending;
    }

    // If no column has been selected, display an error dialog  box.
    if (newColumn == null)
    {
        MessageBox.Show("Select a single column and try again.",
            "Error: Invalid Selection", MessageBoxButtons.OK,
            MessageBoxIcon.Error);
    }
    else
    {
        dataGridView1.Sort(newColumn, direction);
        newColumn.HeaderCell.SortGlyphDirection =
            direction == ListSortDirection.Ascending ?
            SortOrder.Ascending : SortOrder.Descending;
    }
}
  

Ответ №4:

Есть более простой способ. Вы должны установить тип данных столбца следующим образом:

 private void DataGridView1_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
  if (e.Column.Index == 0)
  {
    e.Column.ValueType = typeof(int);
    e.Column.CellTemplate.ValueType = typeof(int);
  }
}
  

или, если у вас есть имя объекта столбца:

 ColumnName.ValueType = typeof(int);