How to display JSON in WPF TreeView

2019-06-02 10:23发布

问题:

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 and End points (above) look fine (presumably because they contain child elements to display).

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?

Thanks for any help!

回答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}}" >


回答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>