С#: пользовательский вид DataGridView
Мне нужно отсортировать DataGridView с естественной сортировкой (как в проводнике), чтобы цифры и текст (в том же столбце) сортировались естественно, а не в алфавитном порядке (так что "место 3" доходит до "места 20" и т.д..). У меня есть DataGridView, где я установил DataView как DataSource. DataView содержит DataTable, который создается с некоторыми значениями из базы данных. Типы столбцов - это строка. У меня есть IComparer, который делает то, что должен, но я не могу понять, как его использовать, потому что я не могу узнать, как выполнить сортировку. Событие DataGridView.SortCompare, которое было бы идеальным, не работает, поскольку оно является привязкой к базе данных. DataView.Sort принимает только строки с именами столбцов и порядками сортировки.
Очень раздражает. Пытался прочитать связанные проблемы здесь, в StackOverflow, и искал много лотов и лотов Google, но я не могу найти много об этом. Только то, что я действительно нахожу, это метод Sort (string) для dataview, который не работает, поскольку он сортируется по алфавиту.
Кто-нибудь знает, как это сделать без особых проблем? Это должны быть другие, чем я, борясь с этим? Я действительно не хочу переопределять все классы datagridview или dataview, просто чтобы получить пользовательскую сортировку...
Обновить. Если кто-то задается вопросом, я все еще ищу хороший ответ на эту проблему. Хотя, в то же время, я создал собственный простой класс таблицы, а затем вручную передал его в datagridview вручную. Переопределение метода SortCompare. Немного раздражает, но не слишком сложно, так как мне нужно показывать значения (без редактирования или что-то еще), и поэтому можно преобразовать все в строки.
Ответы
Ответ 1
Взгляните на эту страницу MSDN и этот пост в блоге. В принципе, вам нужно настроить сортировку в источнике данных (будь то объект ObjectDataSource или SqlDataSource) не в GridView.
Насколько я могу судить, класс DataView не поддерживает ничего, кроме простой сортировки по возрастанию/убыванию. Не видя кода, в котором вы загружаете и привязываете данные, трудно составить конкретную рекомендацию, но вы можете либо:
- Загрузите данные в список вместо DataTable, вызовите метод Сортировка в методе сравнения, а затем привяжите его к этому списку.
- Создайте объект ObjectDataSource в коде aspx, который получает данные непосредственно из класса, и настройте этот объект ObjectDataSource для использования вашего IComparer.
Ответ 2
Этот код должен работать. Он похож на ListView ListViewItemSorter. Использование IComparer.
Для использования:
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
MyDataGridHelper.DataGridSort(dgv, e.ColumnIndex);
}
MyDataGridHelper.cs:
public class MyDataGridHelper
{
public static void DataGridSort(DataGridView dgv, int column)
{
DataGridViewCustomSorter dgvSorter = null;
if (dgv.Tag == null || !(dgv.Tag is IComparer))
{
dgvSorter = new DataGridViewCustomSorter(dgv);
dgv.Tag = dgvSorter;
}
else
{
dgvSorter = (DataGridViewCustomSorter)dgv.Tag;
}
dgvSorter.SortColumn = column;
dgv.Sort(dgvSorter);
}
private class DataGridViewCustomSorter : IComparer
{
private int ColumnIndex;
private SortOrder OrderOfSort;
private DataGridView myDataGridView;
private TypeCode mySortTypeCode;
public DataGridViewCustomSorter(DataGridView dgv)
{
myDataGridView = dgv;
mySortTypeCode = Type.GetTypeCode(Type.GetType("System.String"));
ColumnIndex = 0;
OrderOfSort = SortOrder.None;
}
public int Compare(object x, object y)
{
int result;
DataGridViewRow dgvX, dgvY;
dgvX = (DataGridViewRow)x;
dgvY = (DataGridViewRow)y;
string sx = dgvX.Cells[ColumnIndex].Value.ToString();
string sy = dgvY.Cells[ColumnIndex].Value.ToString();
//null handling
if (sx == String.Empty && sy == String.Empty)
result = 0;
else if (sx == String.Empty && sy != String.Empty)
result = -1;
else if (sx != String.Empty && sy == String.Empty)
result = 1;
else
{
switch (mySortTypeCode)
{
case TypeCode.Decimal:
Decimal nx = Convert.ToDecimal(sx);
Decimal ny = Convert.ToDecimal(sy);
result = nx.CompareTo(ny);
break;
case TypeCode.DateTime:
DateTime dx = Convert.ToDateTime(sx);
DateTime dy = Convert.ToDateTime(sy);
result = dx.CompareTo(dy);
break;
case TypeCode.String:
result = (new CaseInsensitiveComparer()).Compare(sx, sy);
break;
default:
result = (new CaseInsensitiveComparer()).Compare(sx, sy);
break;
}
}
if (OrderOfSort == SortOrder.Descending)
result = (-result);
return result;
}
public int SortColumn
{
set
{
if (ColumnIndex == value)
{
OrderOfSort = (OrderOfSort == SortOrder.Descending ? SortOrder.Ascending : SortOrder.Descending);
}
ColumnIndex = value;
try
{
mySortTypeCode = Type.GetTypeCode(Type.GetType((myDataGridView.Columns[ColumnIndex]).Tag.ToString()));
}
catch
{
mySortTypeCode = TypeCode.String;
}
}
get { return ColumnIndex; }
}
public SortOrder Order
{
set { OrderOfSort = value; }
get { return OrderOfSort; }
}
} //end class DataGridViewCustomSorter
} //end class MyDataGridHelper
Ответ 3
Вы можете создать 2 скрытых столбца. Присвойте текстовую часть 1-му скрытому столбцу и номеру номера ко 2-му скрытому столбцу. Теперь отсортируйте по этим скрытым столбцам (альфа-сортировка для 1-го столбца и числовая сортировка для 2-го столбца).
Таким образом, вы можете сохранить исходный столбец для целей отображения и иметь 2 скрытых столбца для сортировки.
Ответ 4
Здесь есть некоторое решение " Пользовательская сортировка с использованием события SortCompare" и " Пользовательская сортировка с использованием интерфейса IComparer":
http://msdn.microsoft.com/en-us/library/ms171608.aspx
Ответ 5
Вы можете переместить логику сортировки в запрос к базе данных и вернуть ей дополнительный столбец, который имел правильный порядок сортировки.
Затем (по строкам ответа @True C Sharp) вы можете иметь скрытый столбец, содержащий это значение, и сортировать его, а не столбец отображения.
Это предполагает, что логика определения порядка сортировки может быть выполнена в SQL. Это может не сработать, если алгоритм определения порядка сортировки является сложным.