问题
How do I sort a DataGridView by two columns (ascending)? I have two columns: day
and status
.
If I need to sort by one column, I do:
this.dataGridView1.Sort (this.dataGridView1.Columns["day"], ListSortDirection.Ascending);
But for two?
回答1:
If your DataGridView
is databound, you can sort your Datatable
view and rebind to datatable as below:
private DataGridView dataGridView1 = new DataGridView();
private BindingSource bindingSource1 = new BindingSource();
private void Form1_Load(object sender, System.EventArgs e)
{
// Bind the DataGridView to the BindingSource
dataGridView1.DataSource = bindingSource1;
SortDataByMultiColumns(); //Sort the Data
}
private void SortDataByMultiColumns()
{
DataView view = dataTable1.DefaultView;
view.Sort = "day ASC, status DESC";
bindingSource1.DataSource = view; //rebind the data source
}
OR, without using bindingsource and binding directly to DataView
:
private void SortDataByMultiColumns()
{
DataView view = ds.Tables[0].DefaultView;
view.Sort = "day ASC, status DESC";
dataGridView1.DataSource = view; //rebind the data source
}
回答2:
Add a hidden column that combines the two and sort by that.
回答3:
TLDR; I have a two-line solution.
I had to do the same thing, but after researching all these complicated ways to do this by either including a separate .dll or writing my own class/methods, I knew there had to be an easier way. It turns out I was right because I figured out how to accomplish this with using only two lines of code. This worked for me.
Luckily, it turns out for us that the .NET Framework Sort() method does help us with this. The idea is that you want to sort the columns individually, but the order in which you sort them in is what will produce the desired output.
So, as an example, I have a column for file type and a column for a file name. Whenever I want to sort the data by the types, I want to make sure that the names are also sorted within each type shown.
GOAL: Sorting by type will also sort the file names alphabetically.
Data:
zxcv.css
testimg3.jpg
asdf.html
testimg2.jpg
testimg1.jpg
Sorting data by name:
mConflictsDataGridView.Sort(mConflictsDataGridView.Columns[mNameLabel.Index], ListSortDirection.Ascending);
asdf.html
testimg1.jpg
testimg2.jpg
testimg3.jpg
zxcv.css
As you can see, this will name sure that the names will be sorted accordingly, such that when I now sort by the file types, both requirements will satisfy.
Sorting data by file type:
mConflictsDataGridView.Sort(mConflictsDataGridView.Columns[mFileExtensionLabel.Index], ListSortDirection.Ascending);
zxcv.css
asdf.html
testimg1.jpg
testimg2.jpg
testimg3.jpg
Voila! It's sorted!
SOLUTION: In your case, you may want to try something like the following, and you may need to tweak it some more to have it cater to your own code.
DataGridView1.Sort(DataGridView1.Columns["status"], ListSortDirection.Ascending);
DataGridView1.Sort(DataGridView1.Columns["day"], ListSortDirection.Asscending);
This should be able to display your results by the day with its status field sorted as well.
回答4:
You can use the DataGridView's Sort method, but specify an argument that is an instance of a class that implements IComparer.
Here is an example of such a class:
public class MyTwoColumnComparer : System.Collections.IComparer
{
private string _SortColumnName1;
private int _SortOrderMultiplier1;
private string _SortColumnName2;
private int _SortOrderMultiplier2;
public MyTwoColumnComparer(string pSortColumnName1, SortOrder pSortOrder1, string pSortColumnName2, SortOrder pSortOrder2)
{
_SortColumnName1 = pSortColumnName1;
_SortOrderMultiplier1 = (pSortOrder1 == SortOrder.Ascending) ? 1 : -1;
_SortColumnName2 = pSortColumnName2;
_SortOrderMultiplier2 = (pSortOrder2 == SortOrder.Ascending) ? 1 : -1;
}
public int Compare(object x, object y)
{
DataGridViewRow r1 = (DataGridViewRow)x;
DataGridViewRow r2 = (DataGridViewRow)y;
int iCompareResult = _SortOrderMultiplier1 * String.Compare(r1.Cells[_SortColumnName1].Value.ToString(), r2.Cells[_SortColumnName1].Value.ToString());
if (iCompareResult == 0) iCompareResult = _SortOrderMultiplier2 * String.Compare(r1.Cells[_SortColumnName2].Value.ToString(), r2.Cells[_SortColumnName2].Value.ToString());
return iCompareResult;
}
}
Now, we might call this from a column whose SortMode is 'Programmatic' on a mouse click:
private void dgvAllMyEmployees_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
DataGridViewColumn dgvcClicked = dgvAllEmployees.Columns[e.ColumnIndex];
if (dgvcClicked.SortMode == DataGridViewColumnSortMode.Programmatic)
{
_SortOrder = (_SortOrder == SortOrder.Ascending) ? SortOrder.Descending : SortOrder.Ascending;
MyTwoColumnComparer Sort2C = new MyTwoColumnComparer(dgvcClicked.Name, _SortOrder, "LastName", SortOrder.Ascending);
dgvAllEmployees.Sort(Sort2C);
}
}
The class level variable _SortOrder helps keep track of which order to go in. One can enhance this more to remember the last two columns clicked and sort on them in the desired order.
回答5:
You can try this, or use custom sorting:
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].HeaderText =="day")
{
myBindingSource.Sort = "day, hour";
}
}
回答6:
The answer that John Kurtz provided got me close. But what I found was the when I clicked on a column once, it did indeed sort by the two columns ... In his example: dgvcClicked.Name, "LastName". So, good!!
But, if I clicked on the column again, then it would NOT sort by the opposite direction. So the column became stuck in Ascending.
To overcome this, I had to track the sort order manually. Started with this class:
public class ColumnSorting
{
public int ColumnIndex { get; set; }
public ListSortDirection Direction { get; set; }
}
Then, I added this globally scoped List:
List<ColumnSorting> _columnSortingList = new List<ColumnSorting>();
Then, in the method that does the Sort, I would
- Check to see if the column index being sorted already exists in _columnSortingList. If not, add it.
- If it already exists, then swap the sort order
And Bob's your uncle.
回答7:
I use this solution when working with bound data. This works for our users, and displays the current sort criteria. All sorts are only in ascending order.
Add a CheckBox, a TextBox, a ColumnHeaderMouseClick event, and code as shown. The CheckBox will toggle the TextBox's visibility, and clicking on any column header will add the sort criteria to the TextBox. To clear the TextBox, just double click in it.
private void FooDataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if(chkMultiSort.Checked == true)
{
string columnHeader = FooDataGridView.Columns[e.ColumnIndex].DataPropertyName;
txtMultiSort.Text += (columnHeader + ", ");
try
{
FooBindingSource.Sort = txtMultiSort.Text.Remove(txtMultiSort.Text.Length - 2);
}
catch
{
MessageBox.Show("Invalid Sort Data", "Information", MessageBoxButtons.OK, MessageBoxIcon.None);
txtMultiSort.Text = String.Empty;
}
}
}
private void ChkMultiSort_CheckedChanged(object sender, EventArgs e)
{
if(chkMultiSort.Checked == true)
{
txtMultiSort.Visible = true;
}
else
{
txtMultiSort.Visible = false;
txtMultiSort.Text = String.Empty;
}
}
private void TxtMultiSort_DoubleClick(object sender, EventArgs e)
{
txtMultiSort.Text = String.Empty;
}
来源:https://stackoverflow.com/questions/8891390/how-to-sort-a-datagridview-by-2-columns