Сортировка источника данных Datagridview в списке <T>, где T является анонимным - PullRequest
7 голосов
/ 15 января 2011

Относительно простой вопрос.У меня есть datagridview, который все, что он делает, отображает статистику.Нет редактирования / добавления / удаления строк.Сетка данных привязана к списку.Все, чего я хочу добиться, - это чтобы пользователь мог сортировать столбцы.

class Market
{
    public int Location {get;set;}
    public float Value {get;set;}
    //...
}
class City
{
    public String Name {get;set;}
    //...
}

List<Market> _markets;
List<City> _cities;
//Lists are populated.

dataGridView1.DataSource = _markets.Select(market => 
    new { _cities[market.Location].Name, market.Value}).ToList();

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

Это приложение использовало базу данных, у которой были представления,Эти представления затем заполнили DataGridViews.Представления все еще существуют, поэтому возможное решение может быть таким:

DataBase.ViewMarketValue temp = new DataBase.ViewMarketValue()

_markets.ForEach(market => temp.AddViewMarketValueRow(_cities[market.Location].Name, market.Value);
dataGridView1.DataSource = temp;

Это приводит к желаемому: сетевому представлению данных, которое содержит всю информацию и является сортируемым.Единственная проблема заключается в том, что использование представлений в этом аспекте кажется неправильным.Так что мне делать?

Ответы [ 2 ]

11 голосов
/ 16 января 2011

Чтобы иметь возможность автоматически сортировать данные в DataGridView, вам нужна коллекция, которая реализует IBindingListView.В BCL единственными классами, которые реализуют этот интерфейс, являются DataView и BindingSource (но последний поддерживает сортировку, только если базовый источник данных также поддерживает это).

Итак, у вас есть несколько вариантов:

  • создайте DataTable для хранения данных и свяжите его с DataGridView (на самом деле он будет привязан к DefaultView из DataTable)
  • создайте свой собственныйКласс коллекции, который реализует IBindingListView
  • , использует существующую реализацию, например класс AdvancedList<T>, опубликованный Марком Гравеллом в в этом посте .Вам также понадобится добавить конструктор для построения списка из результата вашего запроса:

    public AdvancedList(IEnumerable<T> collection)
    {
        foreach (var item in collection)
        {
            Add(item);
        }
    }
    

Поскольку результат вашего запроса анонимный, вы не будетевозможность вызвать конструктор напрямую.Самый простой способ обойти эту проблему - воспользоваться выводом типа путем создания универсального метода, который создаст список.Для удобства вы можете создать его как метод расширения:

public static AdvancedList<T> ToAdvancedList<T>(this IEnumerable<T> source)
{
    return new AdvancedList<T>(source);
}

Затем вы можете использовать его так:

dataGridView1.DataSource = _markets.Select(market => 
    new { _cities[market.Location].Name, market.Value}).ToAdvancedList();
0 голосов
/ 20 июня 2018

Это то, что я сделал на основе Томаса Левеска (https://stackoverflow.com/a/4702631/1720085) и Мэри Хэмлин (https://stackoverflow.com/a/5805044/1720085) ответы):

1) Добавлен метод расширения в мой статический класс под названием Funcs

static class Funcs
{
    public static DataTable ToDataTable<T>(this IList<T> data)
    {
        PropertyDescriptorCollection properties = 
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                 row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
}

2) И используйте это как:

var query = _markets.Select(market => 
    new { _cities[market.Location].Name, market.Value}).ToList();
dataGridView1.DataSource = Funcs.ToDataTable(query);
...