Bạn có thể thực hiện việc này với Json.NET
khuôn khổ. Json.NET có phương thức tĩnh JToken.Parse()
(có mục đích tương tự với XDocument.Parse()
) và có thể biến một chuỗi JSON hợp lệ thành một hệ thống phân cấp của Newtonsoft.Json.Linq.JToken
các đối tượng. Hệ thống phân cấp này có thể được liên kết thành WPF TreeView
kiểm soát bằng cách sử dụng DataTemplate
và HierarchicalDataTemplate
để định dạng dữ liệu từ tất cả các lớp con có thể có của JToken
và lặp lại thông qua con cái của họ.
Json.NET JToken
bê tông các lớp mà mẫu được yêu cầu là:
Để liên kết hệ thống phân cấp của các lớp này thành một cây, trước tiên bạn cần có trình chuyển đổi
để chuyển đổi JToken.Children()
phương thức thành một thuộc tính:
// Respectfully adapted from https://stackoverflow.com/questions/502250/bind-to-a-method-in-wpf/844946#844946
public sealed class MethodToValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var methodName = parameter as string;
if (value == null || methodName == null)
return null;
var methodInfo = value.GetType().GetMethod(methodName, new Type[0]);
if (methodInfo == null)
return null;
return methodInfo.Invoke(value, new object[0]);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException(GetType().Name + " can only be used for one way conversion.");
}
}
Sau khi thực hiện điều này, một đánh dấu XAML cực kỳ đơn giản có thể hiển thị hệ thống phân cấp này trong cây là:
<Window x:Class="WpfJsonTreeViewNew.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:WpfJsonTreeViewNew"
xmlns:json ="clr-namespace:Newtonsoft.Json;assembly=Newtonsoft.Json"
xmlns:jlinq ="clr-namespace:Newtonsoft.Json.Linq;assembly=Newtonsoft.Json"
Title="Window1" Height="1000" Width="600">
<Window.Resources>
<w:MethodToValueConverter x:Key="MethodToValueConverter"/>
<HierarchicalDataTemplate DataType="{x:Type jlinq:JArray}" ItemsSource="{Binding Converter={StaticResource MethodToValueConverter}, ConverterParameter='Children'}">
<TextBlock Text="Array">
</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type jlinq:JProperty}" ItemsSource="{Binding Converter={StaticResource MethodToValueConverter}, ConverterParameter='Children'}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Property name: "/>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type jlinq:JObject}" ItemsSource="{Binding Converter={StaticResource MethodToValueConverter}, ConverterParameter='Children'}">
<TextBlock Text="Object">
</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type jlinq:JConstructor}" ItemsSource="{Binding Converter={StaticResource MethodToValueConverter}, ConverterParameter='Children'}">
<TextBlock Text="Constructor">
</TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type jlinq:JRaw}" ItemsSource="{Binding Converter={StaticResource MethodToValueConverter}, ConverterParameter='Children'}">
<TextBlock Text="Raw">
</TextBlock>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type jlinq:JValue}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Value: "/>
<TextBox Text="{Binding Path=Value, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<TreeView Margin="3" Name="treeView1">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Grid>
</Window>
Sau đó, khi người dùng của bạn chọn dữ liệu JSON để xem, bạn có thể thực hiện:
var token = JToken.Parse(jsonString);
var children = new List<JToken>();
if (token != null)
{
children.Add(token);
}
treeView1.ItemsSource = null;
treeView1.Items.Clear();
treeView1.ItemsSource = children;
Và kết quả như sau:
Đối với JSON mẫu :
{
""id"": ""0001"",
""type"": ""donut"",
""name"": ""Cake"",
""ppu"": 0.55,
""batters"":
{
""batter"":
[
{ ""id"": ""1001"", ""type"": ""Regular"" },
{ ""id"": ""1002"", ""type"": ""Chocolate"" },
{ ""id"": ""1003"", ""type"": ""Blueberry"" },
{ ""id"": ""1004"", ""type"": ""Devil's Food"" }
]
},
""topping"":
[
{ ""id"": ""5001"", ""type"": ""None"" },
{ ""id"": ""5002"", ""type"": ""Glazed"" },
{ ""id"": ""5005"", ""type"": ""Sugar"" },
{ ""id"": ""5007"", ""type"": ""Powdered Sugar"" },
{ ""id"": ""5006"", ""type"": ""Chocolate with Sprinkles"" },
{ ""id"": ""5003"", ""type"": ""Chocolate"" },
{ ""id"": ""5004"", ""type"": ""Maple"" }
]
}
Tất nhiên, giao diện người dùng có thể được làm đẹp hơn, ví dụ:bằng cách đặt giá trị cho JProperty
mã thông báo chỉ với một JValue
con trên cùng một hàng. Tuy nhiên, điều này sẽ cung cấp cho bạn ý tưởng về cách thực hiện ràng buộc.
Cách tiếp cận này liên kết trực tiếp JSON với cây. Nếu bạn đang tìm kiếm chức năng chỉnh sửa đầy đủ bao gồm thêm, xóa và đổi tên các nút, bạn có thể muốn chuyển sang Phương pháp luận" Model-View-ViewModel "
trong đó JToken
cấu trúc phân cấp trở thành mô hình và mô hình dạng xem nhẹ xử lý các sửa đổi và thông báo.