How to display JSON in WPF TreeView
Asked Answered
B

3

1

I am reading in JSON and then displaying it in a WPF treeview.

Here is the code...

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

And the 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>

Start Point and End Point

Start and End points (above) look fine (presumably because they contain child elements to display).

Phase

But the Phase element should just contain one value. A single string that reads "GROUND". But it is broken up into a charArray for some reason. And displayed in multiple elements as shown above.

So what is the key to fixing this? Multiple data templates that display a string differently from other objects?

Berkeleianism answered 30/3, 2018 at 19:17 Comment(0)
U
1

The problem is that your XAML can only show a collections in dictionary's value and if there is a string, then it will be considered as collection of characters. One of the quick sollutions is to create a converter, which will transform your strings into string collections.

For this you need a value converter(sorry I do code in 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;
    }
}


Instantiate this converter in resources:

<Window.Resources>
<local:ValConv x:Key="valKonv"/>
</Window.Resources>


and use it:

<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
Unquiet answered 30/3, 2018 at 20:39 Comment(1)
Thanks for the answer. It took a little work to get the Vb conversion working but I got it.Berkeleianism
B
2

Here is the code Rekshino submitted, in 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

End 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>

Berkeleianism answered 31/3, 2018 at 1:13 Comment(0)
U
1

The problem is that your XAML can only show a collections in dictionary's value and if there is a string, then it will be considered as collection of characters. One of the quick sollutions is to create a converter, which will transform your strings into string collections.

For this you need a value converter(sorry I do code in 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;
    }
}


Instantiate this converter in resources:

<Window.Resources>
<local:ValConv x:Key="valKonv"/>
</Window.Resources>


and use it:

<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
Unquiet answered 30/3, 2018 at 20:39 Comment(1)
Thanks for the answer. It took a little work to get the Vb conversion working but I got it.Berkeleianism
W
1

I needed a more generic operation to consume any JSON.

This code uses the nuget Newtonsoft JSON to do the magic of taking any raw JSON (without models) and loading it into a TreeView which looks like this:

enter image description here

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 static class JSONOperation

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"}; 
}
Women answered 20/12, 2019 at 21:18 Comment(1)
Missing bracket and semi colon: return new TreeViewItem{ Header = $" \x22{token.Key}\x22 : \x22{outputValue}\x22"};Cantonment

© 2022 - 2024 — McMap. All rights reserved.