2016-01-22 119 views
10

我有一个Windows窗体与datagridview使所有datagridview列可排序

理想的情况:

用户点击任何的九列的,并且程序排序的所有数据,如果单击列包含数字,我想在顶部的最低数量。如果点击的列包含一个字符串,我希望它按字母顺序排序(A-Z)。

我有什么权利现在:

我看到了一个老问题上堆栈溢出,其中OP如何点击“A”标头时,排序在DataGridView。与我的不同之处在于,我希望我的datagridview可以通过九列中的任何一列进行排序。

我有这样的代码,从我找到了被盗的问题:

dataGridView2.DataSource = listPlayers.Select(s => new { voornaam = s.Voornaam, 
                 Achternaam = s.Achternaam, 
                 positie = s.Positie, 
                 Nationaltieit = s.Nationaliteit, 
                 Leeftijd = s.Age, 
                 Aanval = s.Aanval, 
                 Verdediging = s.Verdediging, 
                 Gemiddeld = s.Gemiddeld, 
                 waarde = s.TransferWaarde }) 
            .OrderBy(s => s.Achternaam) 
            .ToList(); 

foreach(DataGridViewColumn column in dataGridView2.Columns) 
    { 
     dataGridView2.Columns[column.Name].SortMode = 
            DataGridViewColumnSortMode.Automatic; 
    } 

这只能通过“Achternaam”让用户订单时,他点击了九列的一个。我想要的是,当用户点击Nationaliteit列时,数据会被An排序。依此类推,每列

这是listplayers列表:

namespace SimulatorSimulator 
{ 
    class SpelerData 
    { 
     public string Voornaam { get; set; } 
     public string Achternaam { get; set; } 
     public string Positie { get; set; } 
     public string Nationaliteit { get; set; } 
     public int Age { get; set; } 
     public int Aanval { get; set; } 
     public int Verdediging { get; set; } 
     public int Gemiddeld { get; set; } 
     public string TransferWaarde { get; set; } 
    } 
} 

,并在主类:

List<SpelerData> listPlayers = new List<SpelerData>(); 

一些假数据:

Romelu;Lukaku;Aanvaller;Belgie;22;87;12;50;41.000.000,00  
Raheem ;Sterling;Aanvaller;Engeland;21;84;30;57;35.000.000,00  
Zlatan ;Ibrahimovic;Aanvaller;Zweden;34;87;21;54;34.500.000,00 
+0

@KevinTinnemans请认真考虑Ivan Stoev对Ian回答的评论。我可能会因为这样说而惹火,而且自从我发布自己的答案之后,这可能会被误解,但接受的答案无法帮助您以任何方式成为更好的开发人员。蛮力是一个跳跃点,当你不能提出更好的解决方案时,你会回避到这个问题上 - 对于这个问题有几个问题。这将导致不好的做法和难以管理的代码。 –

回答

5

我认为你的情况下,最简单的方法是把你的数据在Database表时,点击排序。这样,您可以简单地将此作为您的dataGridView2data source,您将可以通过单击标题列轻松进行排序。

另一种方法是使用SortableBindingListarticle)作为另一个答案也建议。

但是,如果这两个选项都不是你的选择中,我能想到的下一个最简单的方法是从ColumnHeaderMouseClick创建事件,然后你可以列出你通过利用e.ColumnIndex和右边的“映射”因此排序(字典)您准备IEnumerable<SpelerData>

所以,在你的窗体加载,你做这样的事情:

Dictionary<int, IEnumerable<SpelerData>> queryDict = new Dictionary<int, IEnumerable<SpelerData>>(); //Prepare a dictionary of query 
private void form_load(object sender, EventArgs e) { 
    dataGridView2.DataSource = listPlayers.OrderBy(x => x.Achternaam).ToList(); 
    queryDict.Add(0, listPlayers.OrderBy(x => x.Voornaam)); 
    queryDict.Add(1, listPlayers.OrderBy(x => x.Achternaam)); 
    queryDict.Add(2, listPlayers.OrderBy(x => x.Positie)); 
    queryDict.Add(3, listPlayers.OrderBy(x => x.Nationaliteit)); 
    queryDict.Add(4, listPlayers.OrderBy(x => x.Age)); 
    queryDict.Add(5, listPlayers.OrderBy(x => x.Aanval)); 
    queryDict.Add(6, listPlayers.OrderBy(x => x.Verdediging)); 
    queryDict.Add(7, listPlayers.OrderBy(x => x.Gemiddeld)); 
    queryDict.Add(8, listPlayers.OrderBy(x => x.TransferWaarde)); 
} 

然后在ColumnHeaderMouseClick情况下,简单地做:

private void dataGridView2_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { 
    dataGridView2.DataSource = queryDict[e.ColumnIndex].ToList(); 
} 

你会得到你想要的行为。

注意,因为IEnumerable被延迟执行时,Dictionary的前期准备,不会对性能的影响都没有。您需要添加的唯一东西是form_Load中的9行代码,用于准备dataGridView2_ColumnHeaderMouseClick事件中的字典和1行代码。除了前面提到的我可以想到的两个之外,这是最简单的解决方案。

+1

*“除了前面提到的我可以想到的两个之外,这是最简单的解决方案。”*虽然这适用于特定情况,但它更适用于解决方案。如果你需要相同的另一个网格 - 又有10行代码呢?第三个网格等?重新分配数据源的效率非常低,并且有副作用。 'IBindingList'和'IBindingListView'接口是专门用来处理这个和类似的情况。创建一个基本的泛型类可能看起来更多的代码,但它是值得的,因为它是一次性努力,可以在数千个地方重用。 –

4

你可以使用SortableBindingList

SortableBindingList<T> list = new SortableBindingList<T>(); 

//Add items to list 

dataGridView.DataSource = list ; 

这将使列标题

public class SortableBindingList<T> : BindingList<T> 
{ 
    private readonly Dictionary<Type, PropertyComparer<T>> comparers; 
    private bool isSorted; 
    private ListSortDirection listSortDirection; 
    private PropertyDescriptor propertyDescriptor; 

    public SortableBindingList() 
     : base(new List<T>()) 
    { 
     this.comparers = new Dictionary<Type, PropertyComparer<T>>(); 
    } 

    public SortableBindingList(IEnumerable<T> enumeration) 
     : base(new List<T>(enumeration)) 
    { 
     this.comparers = new Dictionary<Type, PropertyComparer<T>>(); 
    } 

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

    protected override bool IsSortedCore 
    { 
     get { return this.isSorted; } 
    } 

    protected override PropertyDescriptor SortPropertyCore 
    { 
     get { return this.propertyDescriptor; } 
    } 

    protected override ListSortDirection SortDirectionCore 
    { 
     get { return this.listSortDirection; } 
    } 

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

    protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction) 
    { 
     List<T> itemsList = (List<T>)this.Items; 

     Type propertyType = property.PropertyType; 
     PropertyComparer<T> comparer; 
     if (!this.comparers.TryGetValue(propertyType, out comparer)) 
     { 
      comparer = new PropertyComparer<T>(property, direction); 
      this.comparers.Add(propertyType, comparer); 
     } 

     comparer.SetPropertyAndDirection(property, direction); 
     itemsList.Sort(comparer); 

     this.propertyDescriptor = property; 
     this.listSortDirection = direction; 
     this.isSorted = true; 

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

    protected override void RemoveSortCore() 
    { 
     this.isSorted = false; 
     this.propertyDescriptor = base.SortPropertyCore; 
     this.listSortDirection = base.SortDirectionCore; 

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

    protected override int FindCore(PropertyDescriptor property, object key) 
    { 
     int count = this.Count; 
     for (int i = 0; i < count; ++i) 
     { 
      T element = this[i]; 
      if (property.GetValue(element).Equals(key)) 
      { 
       return i; 
      } 
     } 

     return -1; 
    } 
} 
1

如果您愿意使用反射,您可以执行如下操作。

注意:我假设您使用的是DataGridView.ColumnHeaderMouseClick Event,但这并没有改变这种方法的核心。重点是您需要动态识别代表您想要的列名称的字符串值OrderBy。如果您真的需要/想要,您可以对此关联进行硬编码。

private void dataGridView2_ColumnHeaderMouseClick(
    object sender, DataGridViewCellMouseEventArgs e) 
{ 
    ... 
    var sortCol = dataGridView2.Columns[e.ColumnIndex]; 
    var colName = sortCol.Name; 

    dataGridView2.DataSource = listPlayers.Select(s => new { voornaam = s.Voornaam, Achternaam = s.Achternaam, positie = s.Positie, Nationaltieit = s.Nationaliteit, Leeftijd = s.Age, Aanval = s.Aanval, Verdediging = s.Verdediging, Gemiddeld = s.Gemiddeld, waarde = s.TransferWaarde }) 
              .OrderBy(s => typeof(SpelerData).GetProperty(colName)) 
              .ToList(); 
    ... 
}