C# 从JSON模式创建WPF UI

C# 从JSON模式创建WPF UI,c#,json,wpf,jsonschema,C#,Json,Wpf,Jsonschema,有没有办法使用JSON模式创建WPF UI?我知道,在AngularJS和其他人的帮助下,可以将其转换为HTML表单。但是,寻找一种用同样的方法创建WPF的方法并没有取得成果 存在一个 介绍如何创建可视Json编辑器。我的要求与这里给出的略有不同。在我的例子中,我想基于模式和模式中提到的属性创建WPF控件。而且,在UI的帮助下,我希望能够通过在UI控件中输入值来创建尽可能多的JSON对象 例如,让我们考虑下面的JSON模式作为示例。 { "$schema": "http://json-sch

有没有办法使用JSON模式创建WPF UI?我知道,在AngularJS和其他人的帮助下,可以将其转换为HTML表单。但是,寻找一种用同样的方法创建WPF的方法并没有取得成果

存在一个 介绍如何创建可视Json编辑器。我的要求与这里给出的略有不同。在我的例子中,我想基于模式和模式中提到的属性创建WPF控件。而且,在UI的帮助下,我希望能够通过在UI控件中输入值来创建尽可能多的JSON对象

例如,让我们考虑下面的JSON模式作为示例。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "definitions": {},
  "id": "http://example.com/example.json",
  "properties": {
    "checked": {
      "default": false,
      "description": "An explanation about the purpose of this instance.",
      "id": "/properties/checked",
      "title": "The Checked Schema",
      "type": "boolean"
    },
    "dimensions": {
      "id": "/properties/dimensions",
      "properties": {
        "height": {
          "default": 10,
          "description": "An explanation about the purpose of this instance.",
          "id": "/properties/dimensions/properties/height",
          "title": "The Height Schema",
          "type": "integer"
        },
        "width": {
          "default": 5,
          "description": "An explanation about the purpose of this instance.",
          "id": "/properties/dimensions/properties/width",
          "title": "The Width Schema",
          "type": "integer"
        }
      },
      "type": "object"
    },
    "id": {
      "default": 1,
      "description": "An explanation about the purpose of this instance.",
      "id": "/properties/id",
      "title": "The Id Schema",
      "type": "integer"
    },
    "name": {
      "default": "A green door",
      "description": "An explanation about the purpose of this instance.",
      "id": "/properties/name",
      "title": "The Name Schema",
      "type": "string"
    },
    "price": {
      "default": 12.5,
      "description": "An explanation about the purpose of this instance.",
      "id": "/properties/price",
      "title": "The Price Schema",
      "type": "number"
    },
    "tags": {
      "id": "/properties/tags",
      "items": {
        "default": "home",
        "description": "An explanation about the purpose of this instance.",
        "id": "/properties/tags/items",
        "title": "The Empty Schema",
        "type": "string"
      },
      "type": "array"
    }
  },
  "type": "object"
}
我希望能够显示
checked
属性的复选框。类似地,一个
GroupBox
或带有2个
TextBox
的东西控制输入尺寸(高度和宽度)。此UI应允许用户输入所需的值,根据这些值可以生成JSON对象。大概

{
  "checked": false,
  "dimensions": {
    "width": 5,
    "height": 10
  },
  "id": 1,
  "name": "A green door",
  "price": 12.5,
  "tags": [
    "home",
    "green"
  ]
}
目前,我正在创建一个
JSchema
对象列表,并将每个属性反序列化为
JSchema
类型,然后将其添加到列表中。此后,我将尝试为相同的对象创建控件。这真是一团糟,我还没有完全达到我的目标。然而,我并不认为我会对最终结果感到满意。如果你能提出一个实现同样目标的方法,那将是非常有帮助的。谢谢


因此,这当然是可能的。您需要做的是定义反序列化例程,使实现
inotifypropertychanged
List/ObservableCollection
对象。您可以通过
newtonsoftjson
或编写
JSchema
ViewModel
转换器来实现这一点

接下来,您可以将
ContentControl
甚至
Listbox/StackPanel
绑定到此可枚举对象,就像主详细视图一样,并且详细视图可以在选定对象上实现
属性网格

确保所有绑定都是双向的,以保留所做的更改。 此外,您可以在
StackPanel
上实现
OnSelectionChanged
事件来序列化更改

资源


我想为UWP做同样的事情,但没有找到一个可行的解决方案。 除了上面提到的PropertyGrid,我还发现 来自Windows社区工具包和Telerik。 使用这些仍然需要将Json转换为对象模型并返回。 事实证明,Newtonsoft.Json是在考虑数据绑定的情况下构建的,因此从Json生成绑定到Json属性的控件非常容易。 下面是一段代码片段:

private void RenderForm(JArray jArray)
{
    StackPanel stackPanel = new StackPanel() { Orientation = Orientation.Vertical };
    this.Content = stackPanel;
    stackPanel.Height = this.Height;
    stackPanel.Width = this.Width;
    stackPanel.Children.Add(button);
    foreach (JObject element in jArray)
    {
        String type = element["type"].ToString();
        TextBlock textBlock = new TextBlock() { Text = element["name"].ToString() };
        textBlock.Padding = new Thickness() { Top = 5 };
        switch (type)
        {
            case "hiddendata":
                break;
            case "bool":
                CheckBox checkBox = new CheckBox();
                checkBox.DataContext = element;
                Binding checkBoxBinding = new Binding() { Path = new PropertyPath("[value].Value"), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
                checkBoxBinding.Source = element;
                checkBox.SetBinding(CheckBox.IsCheckedProperty, checkBoxBinding);
                stackPanel.Children.Add(textBlock);
                stackPanel.Children.Add(checkBox);
                break;
            case "image":
                if (!String.IsNullOrEmpty(element["value"].Value<String>()))
                {
                    Image image = new Image();
                    image.MaxHeight = 200;
                    image.MaxWidth = 200;
                    var ignore = SetImageSource(element["value"].Value<String>(), image);
                    stackPanel.Children.Add(textBlock);
                    stackPanel.Children.Add(image);
                }
                break;
            case "info":
                if (!String.IsNullOrEmpty(element["value"].Value<String>()))
                {
                    TextBlock displayTextBlock = new TextBlock();
                    displayTextBlock.DataContext = element;
                    Binding displayTextBlockBinding = new Binding() { Path = new PropertyPath("[value].Value"), Mode = BindingMode.OneWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
                    displayTextBlockBinding.Source = element;
                    displayTextBlock.SetBinding(TextBlock.TextProperty, displayTextBlockBinding);
                    stackPanel.Children.Add(textBlock);
                    stackPanel.Children.Add(displayTextBlock);
                }
                break;
            case "password":
                PasswordBox passwordBox = new PasswordBox();
                passwordBox.DataContext = element;
                Binding passwordBoxBinding = new Binding() { Path = new PropertyPath("[value].Value"), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
                passwordBoxBinding.Source = element;
                passwordBox.SetBinding(PasswordBox.PasswordProperty, passwordBoxBinding);
                stackPanel.Children.Add(textBlock);
                stackPanel.Children.Add(passwordBox);
                break;
            case "string":
            default:
                TextBox textBox = new TextBox();
                textBox.DataContext = element;
                Binding textBoxBinding = new Binding() { Path = new PropertyPath("[value].Value"), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
                textBoxBinding.Source = element;
                textBox.SetBinding(TextBox.TextProperty, textBoxBinding);
                stackPanel.Children.Add(textBlock);
                stackPanel.Children.Add(textBox);
                break;
        }
    }
}
private void RenderForm(JArray-JArray)
{
StackPanel StackPanel=new StackPanel(){Orientation=Orientation.Vertical};
this.Content=stackPanel;
stackPanel.Height=此.Height;
stackPanel.Width=此.Width;
stackPanel.Children.Add(按钮);
foreach(jArray中的JObject元素)
{
字符串类型=元素[“类型”]。ToString();
TextBlock TextBlock=new TextBlock(){Text=element[“name”].ToString()};
textBlock.Padding=新厚度(){Top=5};
开关(类型)
{
案例“隐藏数据”:
打破
案例“bool”:
复选框=新复选框();
checkBox.DataContext=element;
Binding checkBoxBinding=new Binding(){Path=new PropertyPath(“[value].value”),Mode=BindingMode.TwoWay,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};
checkBoxBinding.Source=元素;
checkBox.SetBinding(checkBox.IsCheckedProperty,checkBoxBinding);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(复选框);
打破
案例“图像”:
如果(!String.IsNullOrEmpty(元素[“value”].value()))
{
图像=新图像();
image.MaxHeight=200;
image.MaxWidth=200;
var ignore=SetImageSource(元素[“值”].value(),图像);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(图像);
}
打破
案例“信息”:
如果(!String.IsNullOrEmpty(元素[“value”].value()))
{
TextBlock displayTextBlock=新建TextBlock();
displayTextBlock.DataContext=元素;
Binding displayTextBlockBinding=new Binding(){Path=new PropertyPath(“[value].value”),Mode=BindingMode.OneWay,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};
displayTextBlockBinding.Source=元素;
displayTextBlock.SetBinding(TextBlock.TextProperty,displayTextBlockBinding);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(displayTextBlock);
}
打破
案例“密码”:
PasswordBox PasswordBox=new PasswordBox();
passwordBox.DataContext=元素;
Binding passwordBoxBinding=new Binding(){Path=new PropertyPath(“[value].value”),Mode=BindingMode.TwoWay,UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged};
passwordBoxBinding.Source=元素;
设置绑定(passwordBox.PasswordProperty,passwordBoxBinding);
stackPanel.Children.Add(textBlock);
stackPanel.Children.Add(密码箱);
打破
大小写“字符串”:
违约:
TextBox TextBox=新建TextBox();
textBox.DataContext=元素;
Binding textBoxBinding=新绑定(){Path=