I have a Windows form with a datagridview
.
The ideal situation:
User clicks on any of the nine columns, and the program sorts all the data, if the clicked column contains numbers, I would like the lowest number on the top. If the clicked column contains a string I would like it to be sorted Alphabetically (A-Z).
What I have right now:
I saw an old question on Stack Overflow where the OP how to sort the datagridview when clicking "a" header. The difference with mine is that I want my datagridview to be sortable by any of the nine columns.
I have this code, stolen from the question I found:
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;
}
This only lets the user order by "Achternaam" when he clicks one of the nine columns. What I want is when the user clicks on the Nationaliteit column, the data gets sorted with the An on top. And so on for every column
This is the listplayers list:
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; }
}
}
And in the main class:
List<SpelerData> listPlayers = new List<SpelerData>();
Some dummy data:
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
I do think that the simplest way for your case would be to put up your data in a Database
table. This way, you could simply use this as the data source
for your dataGridView2
, and you will be able to do your sorting easily by clicking the header column.
An alternative way will be to use SortableBindingList (article) as the other answer has also suggested.
But if both options are not among your choices, the next simplest way I could think of is by creating event from ColumnHeaderMouseClick
, and then you could list your sorting accordingly by making use of e.ColumnIndex
and right "mapping" (Dictionary) to your prepared IEnumerable<SpelerData>
So, in your form load, you do something like this:
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));
}
And then in the ColumnHeaderMouseClick
event, simply do:
private void dataGridView2_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
dataGridView2.DataSource = queryDict[e.ColumnIndex].ToList();
}
And you will get the behavior that you want.
Note that since IEnumerable
is delayed execution, the early preparation of the Dictionary
will not have impact on the performance at all. The only thing you need to add are the 9 lines of code in the form_Load to prepare the dictionary and 1 line of code in your dataGridView2_ColumnHeaderMouseClick
event. This is the simplest solution apart from the two I mentioned earlier which I could think of.
You could use a SortableBindingList
SortableBindingList<T> list = new SortableBindingList<T>();
//Add items to list
dataGridView.DataSource = list ;
This will allow sorting when clicking on the column header
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With