如何在 WPF TreeView 中显示 JSON
How to display JSON in WPF TreeView
我正在阅读 JSON,然后在 WPF 树视图中显示它。
这是代码...
Class MainWindow
Public Sub New()
InitializeComponent()
Dim dic = GetThreadedObject(GetJASN())("phases")
Dim items = dic(0)
tView.ItemsSource = items
End Sub
Private Function GetJASN() As String
Dim output As String = My.Computer.FileSystem.ReadAllText(My.Application.Info.DirectoryPath & "\UAL525 Phase of Flight.json")
Return output
End Function
Private Function GetThreadedObject(JASN As String)
Dim Js As New JavaScriptSerializer()
Js.MaxJsonLength = JASN.Length * 2
Dim j = Js.Deserialize(Of Object)(JASN)
Return j
End Function
End Class
还有 WPF...
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TreeView x:Name="tView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value}" >
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
起点和终点(上方)看起来不错(可能是因为它们包含要显示的子元素)。
但是 Phase 元素应该只包含一个值。读取 "GROUND" 的单个字符串。但由于某种原因,它被分解成一个 charArray。并在多个元素中显示如上图
那么解决这个问题的关键是什么?显示与其他对象不同的字符串的多个数据模板?
问题是你的XAML只能显示字典值中的集合,如果有string
,那么它会被认为是字符集合。快速解决方案之一是创建一个转换器,它将您的字符串转换为字符串集合。
为此你需要一个值转换器(抱歉我用 c# 编写代码)
public class ValConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string str)
{
return new List<string> { str };
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
在资源中实例化此转换器:
<Window.Resources>
<local:ValConv x:Key="valKonv"/>
</Window.Resources>
并使用它:
<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
这是 Rekshino 在 Vb.
中提交的代码
Imports System.Globalization
Public Class ValConv
Implements IValueConverter
Private Function IValueConverter_Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
If (TypeOf value Is String) Then
Dim newStr As New List(Of String)
newStr.Add(value)
Return newStr
Else
Return value
End If
End Function
Private Function IValueConverter_ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
Return value
End Function
结束Class
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:ValConv x:Key="valConv"/>
</Window.Resources>
<Grid>
<TreeView x:Name="tView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
我需要一个更通用的操作来消耗任何 JSON。
此代码使用 nuget Newtonsoft JSON 来实现获取任何原始 JSON(无模型)并将其加载到如下所示的 TreeView
中的魔力:
JSON
string jsonString = @"[{""BatchId"":0,""AccessionChanges"":[{""LabId"":8675309,""InstanceChanges"":[{""Property"":""Note"",""ChangedTo"":""Jabberwocky"",""UniqueId"":null,""SummaryInstance"":null},{""Property"":""Instrument"",""ChangedTo"":""instrumented"",""UniqueId"":null,""SummaryInstance"":null}],""DetailChanges"":[{""Property"":""Comments"",""ChangedTo"":""2nd Comment"",""UniqueId"":null,""SummaryInstance"":null},{""Property"":""CCC"",""ChangedTo"":""XR71"",""UniqueId"":null,""SummaryInstance"":null}]}]}]";
Xaml <TreeView x:Name="tView" />
Codbehind Xaml
InitializeComponent();
try
{
tView.Items.Add(JSONOperation.Json2Tree(JArray.Parse(jsonString), "Root"));
}
catch (JsonReaderException jre)
{
MessageBox.Show($"Invalid Json {jre.Message}");
}
public静态classJSON操作
public static TreeViewItem Json2Tree(JToken root, string rootName = "")
{
var parent = new TreeViewItem() { Header = rootName };
foreach (JToken obj in root)
foreach (KeyValuePair<string, JToken> token in (JObject)obj)
switch (token.Value.Type)
{
case JTokenType.Array:
var jArray = token.Value as JArray;
if (jArray?.Any() ?? false)
parent.Items.Add(Json2Tree(token.Value as JArray, token.Key));
else
parent.Items.Add($"\x22{token.Key}\x22 : [ ]"); // Empty array
break;
case JTokenType.Object:
parent.Items.Add(Json2Tree((JObject)token.Value, token.Key));
break;
default:
parent.Items.Add(GetChild(token));
break;
}
return parent;
}
private static TreeViewItem GetChild(KeyValuePair<string, JToken> token)
{
var value = token.Value.ToString();
var outputValue = string.IsNullOrEmpty(value) ? "null" : value;
return new TreeViewItem() { Header = $" \x22{token.Key}\x22 : \x22{outputValue}\x22"};
}
我正在阅读 JSON,然后在 WPF 树视图中显示它。
这是代码...
Class MainWindow
Public Sub New()
InitializeComponent()
Dim dic = GetThreadedObject(GetJASN())("phases")
Dim items = dic(0)
tView.ItemsSource = items
End Sub
Private Function GetJASN() As String
Dim output As String = My.Computer.FileSystem.ReadAllText(My.Application.Info.DirectoryPath & "\UAL525 Phase of Flight.json")
Return output
End Function
Private Function GetThreadedObject(JASN As String)
Dim Js As New JavaScriptSerializer()
Js.MaxJsonLength = JASN.Length * 2
Dim j = Js.Deserialize(Of Object)(JASN)
Return j
End Function
End Class
还有 WPF...
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TreeView x:Name="tView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value}" >
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
起点和终点(上方)看起来不错(可能是因为它们包含要显示的子元素)。
但是 Phase 元素应该只包含一个值。读取 "GROUND" 的单个字符串。但由于某种原因,它被分解成一个 charArray。并在多个元素中显示如上图
那么解决这个问题的关键是什么?显示与其他对象不同的字符串的多个数据模板?
问题是你的XAML只能显示字典值中的集合,如果有string
,那么它会被认为是字符集合。快速解决方案之一是创建一个转换器,它将您的字符串转换为字符串集合。
为此你需要一个值转换器(抱歉我用 c# 编写代码)
public class ValConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string str)
{
return new List<string> { str };
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
在资源中实例化此转换器:
<Window.Resources>
<local:ValConv x:Key="valKonv"/>
</Window.Resources>
并使用它:
<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
这是 Rekshino 在 Vb.
中提交的代码Imports System.Globalization
Public Class ValConv
Implements IValueConverter
Private Function IValueConverter_Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
If (TypeOf value Is String) Then
Dim newStr As New List(Of String)
newStr.Add(value)
Return newStr
Else
Return value
End If
End Function
Private Function IValueConverter_ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
Return value
End Function
结束Class
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:ValConv x:Key="valConv"/>
</Window.Resources>
<Grid>
<TreeView x:Name="tView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
我需要一个更通用的操作来消耗任何 JSON。
此代码使用 nuget Newtonsoft JSON 来实现获取任何原始 JSON(无模型)并将其加载到如下所示的 TreeView
中的魔力:
JSON
string jsonString = @"[{""BatchId"":0,""AccessionChanges"":[{""LabId"":8675309,""InstanceChanges"":[{""Property"":""Note"",""ChangedTo"":""Jabberwocky"",""UniqueId"":null,""SummaryInstance"":null},{""Property"":""Instrument"",""ChangedTo"":""instrumented"",""UniqueId"":null,""SummaryInstance"":null}],""DetailChanges"":[{""Property"":""Comments"",""ChangedTo"":""2nd Comment"",""UniqueId"":null,""SummaryInstance"":null},{""Property"":""CCC"",""ChangedTo"":""XR71"",""UniqueId"":null,""SummaryInstance"":null}]}]}]";
Xaml <TreeView x:Name="tView" />
Codbehind Xaml
InitializeComponent();
try
{
tView.Items.Add(JSONOperation.Json2Tree(JArray.Parse(jsonString), "Root"));
}
catch (JsonReaderException jre)
{
MessageBox.Show($"Invalid Json {jre.Message}");
}
public静态classJSON操作
public static TreeViewItem Json2Tree(JToken root, string rootName = "")
{
var parent = new TreeViewItem() { Header = rootName };
foreach (JToken obj in root)
foreach (KeyValuePair<string, JToken> token in (JObject)obj)
switch (token.Value.Type)
{
case JTokenType.Array:
var jArray = token.Value as JArray;
if (jArray?.Any() ?? false)
parent.Items.Add(Json2Tree(token.Value as JArray, token.Key));
else
parent.Items.Add($"\x22{token.Key}\x22 : [ ]"); // Empty array
break;
case JTokenType.Object:
parent.Items.Add(Json2Tree((JObject)token.Value, token.Key));
break;
default:
parent.Items.Add(GetChild(token));
break;
}
return parent;
}
private static TreeViewItem GetChild(KeyValuePair<string, JToken> token)
{
var value = token.Value.ToString();
var outputValue = string.IsNullOrEmpty(value) ? "null" : value;
return new TreeViewItem() { Header = $" \x22{token.Key}\x22 : \x22{outputValue}\x22"};
}