Привязка массива массивов или динамического к сетке данных

Я пытаюсь привязать массив массивов к 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;
    }

Это код, который связывает представление, вызываемое в представлении.

Куда:

  1. _dynamicReportPreview является именованной сеткой в ​​XAML.

  2. 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;
            }
        }
    }
    
Другие вопросы по тегам