Привязка массива массивов или динамического к сетке данных
Я пытаюсь привязать массив массивов к DataGrid
,
Я знаю, что я мог бы сделать это довольно легко, преобразовав данные в DataTable
а затем связать это. НО это не то, что мне нужно, так как мне нужно, чтобы иметь возможность добавлять группировки данных через PagedCollectionVIew
,
Причина для этого заключается в следующем: у меня есть набор элементов управления, которые создают структуру для документа, и я хочу динамически отражать эту структуру с помощью фиктивных данных, пока используются элементы управления структурой. Фиктивные данные представляют собой простую симметричную матрицу случайных чисел, где строки являются элементами данных. Я хочу связать каждый столбец сетки с элементами массива, а НЕ с объектом массива.
_dataGenerator = new DummyDataGenerator();
_dummyDataView = new ObservableCollection<int[]>();
DummyData = new PagedCollectionView(_dummyDataView);
Где _dummyDataView
населён
// Set up the dummy data for the fields available.
_dataGenerator.CreateData(ReportFields).ForEach(_dummyDataView.Add);
и XAML это просто DataGrid
привязка к DummyData
... тогда я буду динамически добавлять группировки и сортировки, когда пользователь играет с данными документа. Я искал везде, но не могу найти решение, но должен быть способ (кто-то должен был это опубликовать) связать с элементами массива в xaml! Действительно нужна помощь здесь.
1 ответ
У меня есть ответ (ну, у меня он был давным-давно, но я вспомнил, что разместил этот вопрос). Это чудовище из огромного количества фрагментов и моего собственного мозга, так что я не могу приписать всех. Я собираюсь поставить это. Потому что я думаю, что это круто. Даже если никто не заботится
Он использует: - DLR - немного отражения - немного здания IL.
Вероятно, следует поместить все это в сообщение в блоге, но я не веду блог.
Это код, который создает данные для представления, вызываемого ViewModel.
public IEnumerable<dynamic> CreateData(ObservableCollection<ReportFieldVm> reportFields)
{
// Find the length of the array.
var size = reportFields.Count;
// Create matrix.
var b = new int[size, size];
// Random for the values.
var rand = new Random((int)DateTime.Now.Ticks);
// Build the symmetric matrix.
for (var i = 0; i < size; i++)
{
for (var j = 0; j < size; j++)
{
if (i == j)
{
b[i,j] = rand.Next(0, 100);
}
else
{
var a = rand.Next(0, 100);
b[i,j] = a;
b[j,i] = a;
}
}
}
// Define the assembly to add out new type to.
var asmName = new AssemblyName("DummyAssembly");
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
var mb = ab.DefineDynamicModule("DummyModule");
// Define our type.
var d = mb.DefineType("DummyType", TypeAttributes.Public);
const MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
// Define all the fields for the new type.
foreach (var rf in reportFields.OrderBy(rf => rf.SelectOrder))
{
var propertyName = rf.FieldName;
var field = d.DefineField("m_" + propertyName, typeof(int), FieldAttributes.Private);
var property = d.DefineProperty(propertyName, PropertyAttributes.HasDefault, typeof(int), null);
var dGetAccessor = d.DefineMethod("get_" + propertyName, GetSetAttr, typeof(int), Type.EmptyTypes);
var numberGetIl = dGetAccessor.GetILGenerator();
numberGetIl.Emit(OpCodes.Ldarg_0);
numberGetIl.Emit(OpCodes.Ldfld, field);
numberGetIl.Emit(OpCodes.Ret);
var dSetAccessor = d.DefineMethod("set_" + propertyName, GetSetAttr, null, new Type[] { typeof(int) });
var numberSetIl = dSetAccessor.GetILGenerator();
numberSetIl.Emit(OpCodes.Ldarg_0);
numberSetIl.Emit(OpCodes.Ldarg_1);
numberSetIl.Emit(OpCodes.Stfld, field);
numberSetIl.Emit(OpCodes.Ret);
property.SetGetMethod(dGetAccessor);
property.SetSetMethod(dSetAccessor);
}
// Create the type.
var dummyType = d.CreateType();
var array = new List<dynamic>();
// Convert the matrix into the array of the dynamic.
for (var i = 0; i < size; i++)
{
var obj = Activator.CreateInstance(dummyType);
int j = 0;
foreach (var rf in reportFields.OrderBy(rf => rf.SelectOrder))
{
var type = obj.GetType();
var prop = type.GetProperty(rf.FieldName);
prop.SetValue(obj, b[j, i], null);
j++;
}
array.Add(obj);
}
return array;
}
Это код, который связывает представление, вызываемое в представлении.
Куда:
_dynamicReportPreview
является именованной сеткой в XAML.ViewModel
это свойство, которое подвергаетDataContext
представления, установленного в конструкторе представления.private void BuildPreviewGridColumns() { if (_dynamicReportPreview == null) return; _dynamicReportPreview.Columns.Clear(); var initialFields = ViewModel.ReportFields.OrderBy(rf => rf.SelectOrder); foreach (var rf in initialFields) { var col = new Column { ColumnName = rf.FieldName, Binding = new Binding(rf.FieldName) }; _dynamicReportPreview.Columns.Add(col); if (!rf.IsVisible) { col.Visible = false; } } }