如何使用C#将高度嵌套的动态json转换为WPF形式的可编辑表

wljmcqd8  于 2023-03-24  发布在  C#
关注(0)|答案(1)|浏览(130)

已关闭。此问题需要details or clarity。当前不接受答案。
**想要改进此问题?**添加详细信息并通过editing this post阐明问题。

2天前关闭。
Improve this question
我想知道是否有一个简单而最好的方法来转换一个嵌套的json到一个WPF表单上的可编辑表,用户可以编辑该表。编辑完成后,我想再次将编辑后的表转换回json。我是C#的新手。我真的很感激如何实现这一点的任何建议。
PS:JSON是动态的(可以添加或删除新的键,结构可能会改变)。

pvcm50d1

pvcm50d11#

这很简单:

  • 使用System.Text.Json中的类型作为模型
  • 构建一个视图模型来 Package 它(主要有3种类型:JsonArrayJsonObjectJsonValue都是从JsonNode派生的)
  • 要使它能很好地与TreeViewHierarchicalDataTemplate一起工作,视图模型还必须知道与JsonNode匹配的 key

键可以是 root、对象属性名、数组元素索引
这是只读版本的初稿。
代码为here

密钥:

public enum JsonKeyType
{
    Root,
    Index,
    Parameter
}

public abstract class JsonKey
{
    public abstract JsonKeyType KeyType { get; }
}

public class IndexKey : JsonKey
{
    public IndexKey(int index)
    {
        Index = index;
    }

    public int Index { get; }

    public override JsonKeyType KeyType => JsonKeyType.Index;

    public override string ToString() => $"@{Index}";
}

public class PropertyKey : JsonKey
{
    public PropertyKey(string key)
    {
        Key = key;
    }

    public string Key { get; }

    public override JsonKeyType KeyType => JsonKeyType.Parameter;

    public override string ToString() => Key;
}

public class RootKey : JsonKey
{
    public static RootKey Instance { get; } = new();

    private RootKey()
    {
    }

    public override JsonKeyType KeyType => JsonKeyType.Root;

    public override string ToString() => "Root";
}

视图模型:

public abstract class JsonViewModel
{
    public static JsonViewModel? From(JsonKey key, JsonNode? jsonNode)
    {
        return jsonNode switch
        {
            JsonArray jsonArray => new JsonArrayViewModel(key, jsonArray),
            JsonObject jsonObject => new JsonObjectViewModel(key, jsonObject),
            JsonValue jsonValue => new JsonValueViewModel(key, jsonValue),
            null => new JsonValueViewModel(key, null),
            _ => throw new UnreachableException()
        };
    }

    protected JsonViewModel(JsonKey key)
    {
        Key = key;
    }

    public JsonKey Key { get; }
}

public class JsonArrayViewModel : JsonViewModel
{
    private readonly JsonArray _jsonArray;

    public JsonArrayViewModel(JsonKey key, JsonArray jsonArray) : base(key)
    {
        _jsonArray = jsonArray;
    }

    public IEnumerable<JsonViewModel?> Values => _jsonArray.Select((node, index) => From(new IndexKey(index), node));
}

public class JsonObjectViewModel : JsonViewModel
{
    private readonly JsonObject _jsonObject;

    public JsonObjectViewModel(JsonKey key, JsonObject jsonObject) : base(key)
    {
        _jsonObject = jsonObject;
    }

    public IEnumerable<JsonViewModel?> Values => _jsonObject.Select(kvp => From(new PropertyKey(kvp.Key), kvp.Value));
}

public class JsonValueViewModel : JsonViewModel
{
    public JsonValueViewModel(JsonKey key, JsonValue? jsonValue) : base(key)
    {
        if (jsonValue is null)
        {
            Value = "null";
            ValueKind = JsonValueKind.Null;
        }
        else
        {
            var jsonElement = jsonValue.GetValue<JsonElement>();

            Value = jsonElement.GetRawText();
            ValueKind = jsonElement.ValueKind;
        }
    }

    public string Value { get; }

    public JsonValueKind ValueKind { get; }
}

视图:

<TreeView ItemsSource="{Binding}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:JsonArrayViewModel}" ItemsSource="{Binding Values}">
            <TextBlock Text="{Binding Key}" Foreground="Gray" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:JsonObjectViewModel}" ItemsSource="{Binding Values}">
            <TextBlock Text="{Binding Key}" Foreground="Gray" />
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type local:JsonValueViewModel}">
            <StackPanel Orientation="Horizontal"
                        ToolTip="{Binding ValueKind}">
                <TextBlock Text="{Binding Key, StringFormat='{}{0}: '}" Foreground="Gray">
                    <TextBlock.Style>
                        <Style TargetType="TextBlock">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Key.KeyType}" Value="{x:Static local:JsonKeyType.Index}">
                                    <Setter Property="FontStyle" Value="Italic" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
                <TextBlock Text="{Binding Value}" />
            </StackPanel>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

相关问题