Сортировка форматированных значений для DataGridView с привязкой к контексту Entity Framework
Предположим, у меня есть две сущности (весь приведенный ниже код упрощен, чтобы отразить только суть проблемы):
public class TemplateField
{
public Guid Id { get; set; }
public String Name { get; set; }
public String FieldType { get; set; }
}
public class FieldValue
{
public Guid Id { get; set; }
public Guid TemplateFieldId { get; set; }
public Byte[] Value { get; set; }
}
и я использую их в EF DbContext (Code-First):
public class MyContext : DbContext
{
public DbSet<TemplateField> TemplateFields { get; set; }
public DbSet<FieldValue> FieldValues { get; set; }
}
Я использую привязку данных к WinForms DataGridView (согласно этой статье msdn)
private void LoadAndBindEntities()
{
// Call the Load method to get the data for the given DbSet
// from the database.
// The data is materialized as entities. The entities are managed by
// the DbContext instance.
_context.FieldValues.Load();
_context.TemplateFields.Load();
// Bind the categoryBindingSource.DataSource to
// all the Unchanged, Modified and Added Category objects that
// are currently tracked by the DbContext.
// Note that we need to call ToBindingList() on the
// ObservableCollection<TEntity> returned by
// the DbSet.Local property to get the BindingList<T>
// in order to facilitate two-way binding in WinForms.
fieldValuesBindingSource.DataSource = _context.FieldValues.Local.ToBindingList();
templateFieldsBindingSource.DataSource = _context.TemplateFields.Local.ToBindingList();
}
И, наконец, я выполняю форматирование для столбца Value в соответствии с FieldType:
private void DataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
............
e.Value = GetFormattedValue(e.Value as byte[], templateFieldId);
............
}
internal object GetFormattedValue(byte[] value, Guid templateFieldId)
{
............
//Getting FieldType for templateFieldId
............
if (value == null)
return ("NULL");
else
{
if (type == typeof(String))
return (Encoding.Unicode.GetString(value));
else if (type == typeof(DateTime))
return (DateTime.FromBinary(BitConverter.ToInt64(value, 0)));
else if (type == typeof(Boolean))
return (BitConverter.ToBoolean(value, 0));
else if (type == typeof(Int32))
return (BitConverter.ToInt32(value, 0));
else if (type == typeof(Double))
return (BitConverter.ToDouble(value, 0));
else
return ("unknown field type: " + type.Name);
}
}
Моя проблема заключается в том, что пользовательская сортировка (по щелчку заголовка столбца) для столбца " Значение" в DataGridView не работает "из коробки" (SortMode, конечно, имеет значение " Автоматически"). Более того:
- Я не могу использовать событие SortCompare и функцию Sort для DataGridView, потому что DataSource установлен.
- Я не могу реализовать IComparer в классе FieldValue, потому что мне нужно отсортировать отформатированные значения (не оригинальный байтовый массив).
Моя цель - выполнить сортировку по форматированным значениям в столбце " Значение". Как я могу это сделать?
1 ответ
Наконец я сделал это с событием ColumnHeaderMouseClick и динамическим изменением BindingSource (информация была взята из комментариев к этому вопросу)
private void DataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
//clicked column with formatted values
if (e.ColumnIndex == formattedValueColumnIndex)
{
// Sort this column for the first time
if (direction == SortOrder.None)
{
// Remove the SortGlyph for all columns
foreach (DataGridViewColumn column in DataGridView.Columns)
column.HeaderCell.SortGlyphDirection = SortOrder.None;
direction = SortOrder.Ascending;
}
else
// Sort the same column again, reversing the SortOrder for it
direction = direction ==
SortOrder.Ascending
? SortOrder.Descending
: SortOrder.Ascending;
if (direction == SortOrder.Ascending)
fieldValuesBindingSource.DataSource = new BindingList
<FieldValue>(
_context.FieldValues.Local.OrderBy(
item => GetFormattedValue(item.Value, item.TemplateFieldId).ToString())
.ToList());
else
fieldValuesBindingSource.DataSource = new BindingList
<FieldValue>(
_context.FieldValues.Local.OrderByDescending(
item => GetFormattedValue(item.Value, item.TemplateFieldId).ToString())
.ToList());
}
//clicked column with ordinary (not-formatted) value
else
//and column with formatted value was sorted before the click
if (direction != SortOrder.None)
{
direction = SortOrder.None;
fieldValuesBindingSource.DataSource =
_context.FieldValues.Local.ToBindingList();
}
}
void DataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
//clicked column with formatted value - changing SortGlyph for it
if (DataGridView.Columns[formattedValueColumnIndex].HeaderCell.SortGlyphDirection != direction)
logBookFieldValueDataGridView.Columns[formattedValueColumnIndex].HeaderCell.SortGlyphDirection = direction;
}