Как отобразить несколько полей string и массив из string в виде колонок DataGrid?
Здравствуйте!
Есть класс, в нем несколько полей (например, типа string) и поле массив (или List).
Например, есть 3 поля string и в массиве 2 объекта. Тогда необходимо все это отобразить в Datagrid (wpf), в виде 5 колонок.
Суть в том, что я получаю из БД (MongoDB, хотя сами данные идут с API в виде JSON) несколько стандартных полей, а некоторые поля могут добавляться/удаляться, и я заранее не знаю, сколько их всего. Поэтому затрудняюсь в программе написать класс и привязать его к таблице.
Так же есть возможность изменить структуру БД. Главное условие - у пользователей должна быть возможность добавлять или удалять свойства объекта, при этом все текущие свойства должны отображаться в таблице.
Думаю, случай не совсем редкий. Как обычно это реализуют?
Сломал себе голову, помогите, пожалуйста! Буду рад любым советам.
Благодарю.
Для стандартных полей сделай стандартные колонки в разметке, в связанной viewmodel-ке сделай свойства, соотв. стандартным полям, сделай для них обыкновенные биндинги.
Для полей, которые могут удаляться/добавляться - генерируй колонки уже после прихода данных и добавляй в датагрид. Во вьюмодели сделай свойство UserProperties типа IDictionary, и заполняй словарь значениями нестандартных полей. При создании "динамических" колонок назначай им привязки вида UserProperties[propertyName], чтобы датагрид лез в этот словарь у каждого элемента и брал оттуда "пользовательские" свойства.
Это идея, если нужно подробнее - непонятные места в комментарии. Случай действительно не редкий, сам недавно писал весьма похожую вещь - данные в монге (из-за отстуствия какой-либо схемы, "пользовательские" свойства), присылаются в JSON-е, нужно было показать в зависимости от того, что пришло.
Прежде всего, большое спасибо за ответ!
Непонятные места действительно есть, хотя, возможно, я просто туплю:
1. Как генерировать дополнительные колонки после компиляции (ведь в MVVM VM ничего не знает о V, и генерировать их кодом из VM - нарушение паттерна)?
2. Вытекает из п.1 - как эти свойства забиндить?
Возможно, я вас просто неправильно понял. Объясните, пожалуйста, в каком месте должна происходить генерация и байндинг, и совместима ли такая схема с MVVM. Еще раз спасибо.
ber_enot Идея и состоит в том, что она совместима с mvvm на уровне заполняемых данных, но не метаданных. Генерировать колонки вовсе не обязательно во viewmodel, можно это сделать и отдельным кодом в code behind, или даже унаследовать datagrid (как вариант, не уверен что так будет удобнее). Т.к. природа datagrid такова, что все элементы должны содержать одни и те же колонки (т.е. колонки могут добавляться или удаляться, но для всех элементов сразу), то удобнее всего помимо viewmodel-ек элементов иметь еще и общий объект метаданных, в котором будет указан список имен пользовательских свойств. Потом по этом списку генерировать колонки с привязками, ну и словари заполнять во viewmodel тоже.
Итак, еще раз мое предложение: каждая строка datagrid это viewmodel-ка, у нее есть стандартные свойства, которые реализованы как обыкновенные дотнетовские свойства, в самом датагриде есть стандартные колонки с привязками к стандартным свойствам. Как и всегда, ставите datagrid.ItemsSource = itemViewModels; где itemViewModels это List. А вот теперь добавим к этой обычной схеме динамические колонки. В ItemViewModel делаем указанный выше словарь пользовательских свойств. Помимо этого, при получении данных и формировании содержимого List также будем создавать объект метаданных - один на ВСЕ экземпляры ItemViewModel - с именами всех пользовательских свойств. Например, можно сделать такой: class UserPropertyInfo { string name; string displayName; }, где name - это имя для извлечения из словаря, а displayName - отображаемое имя, например, заголовок для колонки в датагриде. И такой список: List. Из приходящих данных мы создаем этот список свойств, ну и собственно список самих ItemViewModel. После этого к стандартным колонкам в датагриде добавляем по одной колонке для каждого UserPropertyInfo с биндингом вроде указанного в ответе. Колонки конечно придется создавать руками в коде, привязки для коллекции колонок наверное сделать не получится.
ber_enot ух ты, нашел отличный вариант с привязкой к коллекции колонок через приаттаченное свойство: stackoverflow.com/questions/320089/how-do-i-bind-a... , так что возможно даже получится сделать полностью в рамках mvvm паттерна, положив коллекцию колонок рядом с коллекцией ItemViewModel в объемлющую ViewModel.
Станислав Макаров , огромное вам спасибо! Сейчас, к сожалению, нет возможности попробовать это реализовать, но как приеду домой - сделаю, и ваш ответ отмечу как решение. (Возможно еще вопросик появится ;). Еще раз спасибо.