Вместо JsonNode
прочитайте Map
и используйте стандарт Map.put()
для изменения большего объекта:
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
TypeReference<Map<String, Object>> type = new TypeReference<>() {};
Map<String, Object> biggerMap = mapper.readValue(biggerJson, type);
Map<String, Object> smallerMap = mapper.readValue(smallerJson, type);
biggerMap.put("additional_info", smallerMap);
String outJson = mapper.writeValueAsString(biggerMap);
System.out.println(outJson);
выведет:
{
"name" : {
"first" : "Tatu",
"last" : "Saloranta"
},
"title" : "Jackson founder",
"company" : "FasterXML",
"additional_info" : {
"country" : "My country",
"hobbies" : "some hobbies"
}
}
Можно добавить GridViewColumns к GridView динамично, учитывая первый массив с помощью метода как это:
private void AddColumns(GridView gv, string[] columnNames)
{
for (int i = 0; i < columnNames.Length; i++)
{
gv.Columns.Add(new GridViewColumn
{
Header = columnNames[i],
DisplayMemberBinding = new Binding(String.Format("[{0}]", i))
});
}
}
Я предполагаю, что второй массив, содержащий значения, будет иметь СТРОКИ * длина СТОЛБЦОВ. В этом случае Ваши объекты могут быть массивами строк СТОЛБЦОВ длины. Можно использовать Массив. Копия или LINQ для разделения массива. Принцип продемонстрирован здесь:
<Grid>
<Grid.Resources>
<x:Array x:Key="data" Type="{x:Type sys:String[]}">
<x:Array Type="{x:Type sys:String}">
<sys:String>a</sys:String>
<sys:String>b</sys:String>
<sys:String>c</sys:String>
</x:Array>
<x:Array Type="{x:Type sys:String}">
<sys:String>do</sys:String>
<sys:String>re</sys:String>
<sys:String>mi</sys:String>
</x:Array>
</x:Array>
</Grid.Resources>
<ListView ItemsSource="{StaticResource data}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=[0]}" Header="column1"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=[1]}" Header="column2"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=[2]}" Header="column3"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
Спасибо, который очень полезен.
Я использовал его для создания динамической версии следующим образом. Я создал заголовки столбцов, как Вы предположили:
private void AddColumns(List<String> myColumns)
{
GridView viewLayout = new GridView();
for (int i = 0; i < myColumns.Count; i++)
{
viewLayout.Columns.Add(new GridViewColumn
{
Header = myColumns[i],
DisplayMemberBinding = new Binding(String.Format("[{0}]", i))
});
}
myListview.View = viewLayout;
}
Создайте ListView очень просто в XAML:
<ListView Name="myListview" DockPanel.Dock="Left"/>
Созданный класс обертки для ObservableCollection для содержания моих данных:
public class MyCollection : ObservableCollection<List<String>>
{
public MyCollection()
: base()
{
}
}
И связанный мой ListView с ним:
results = new MyCollection();
Binding binding = new Binding();
binding.Source = results;
myListview.SetBinding(ListView.ItemsSourceProperty, binding);
Затем для заполнения его он был просто случай убирания любых старых данных и добавления нового:
results.Clear();
List<String> details = new List<string>();
for (int ii=0; ii < externalDataCollection.Length; ii++)
{
details.Add(externalDataCollection[ii]);
}
results.Add(details);
Существуют, вероятно, более опрятные способы сделать его, но это очень полезно для моего приложения. Еще раз спасибо.
This article on the CodeProject explains exactly how to create a Dynamic ListView - when data is known only at runtime. http://www.codeproject.com/KB/WPF/WPF_DynamicListView.aspx
Не уверен, что это все еще актуально, но я нашел способ стилизовать отдельные ячейки с помощью селектора шаблонов ячеек. Это немного взломано, потому что вам нужно пережевывать содержимое ContentPresenter, чтобы получить правильный DataContext для ячейки (чтобы вы могли привязаться к фактическому элементу ячейки в шаблоне ячейки):
public class DataMatrixCellTemplateSelectorWrapper : DataTemplateSelector
{
private readonly DataTemplateSelector _ActualSelector;
private readonly string _ColumnName;
private Dictionary<string, object> _OriginalRow;
public DataMatrixCellTemplateSelectorWrapper(DataTemplateSelector actualSelector, string columnName)
{
_ActualSelector = actualSelector;
_ColumnName = columnName;
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
// The item is basically the Content of the ContentPresenter.
// In the DataMatrix binding case that is the dictionary containing the cell objects.
// In order to be able to select a template based on the actual cell object and also
// be able to bind to that object within the template we need to set the DataContext
// of the template to the actual cell object. However after the template is selected
// the ContentPresenter will set the DataContext of the template to the presenters
// content.
// So in order to achieve what we want, we remember the original DataContext and then
// change the ContentPresenter content to the actual cell object.
// Therefor we need to remember the orginal DataContext otherwise in subsequent calls
// we would get the first cell object.
// remember old data context
if (item is Dictionary<string, object>)
{
_OriginalRow = item as Dictionary<string, object>;
}
if (_OriginalRow == null)
return null;
// get the actual cell object
var obj = _OriginalRow[_ColumnName];
// select the template based on the cell object
var template = _ActualSelector.SelectTemplate(obj, container);
// find the presenter and change the content to the cell object so that it will become
// the data context of the template
var presenter = WpfUtils.GetFirstParentForChild<ContentPresenter>(container);
if (presenter != null)
{
presenter.Content = obj;
}
return template;
}
}
Примечание: я изменил DataMatrix из статью CodeProject, чтобы строки были словарями (ColumnName -> Cell Object).
Я не могу гарантировать, что это решение ничего не сломает или не сломается в будущем выпуске .Net. Он основан на том факте, что ContentPresenter устанавливает DataContext после того, как он выбрал шаблон для своего собственного содержимого. (Reflector очень помогает в этих случаях :))
При создании GridColumns я делаю что-то вроде этого:
var column = new GridViewColumn
{
Header = col.Name,
HeaderTemplate = gridView.ColumnHeaderTemplate
};
if (listView.CellTemplateSelector != null)
{
column.CellTemplateSelector = new DataMatrixCellTemplateSelectorWrapper(listView.CellTemplateSelector, col.Name);
}
else
{
column.DisplayMemberBinding = new Binding(string.Format("[{0}]", col.Name));
}
gridView.Columns.Add(column);
Примечание: я расширил ListView, так что у него есть свойство CellTemplateSelector, к которому вы можете привязать в xaml
@Edit 15/03/2011: Я написал небольшую статью, к которой прикреплен небольшой демонстрационный проект: http://codesilence.wordpress.com/2011/03/15/listview-with-dynamic-columns/