有没有办法使用JSON Schema创建WPF UI?我知道可以在AngularJS和其他人的帮助下将其转换为HTML表单。但是寻找一种创建WPF的方法并不富有成效。
存在Source by Rico Suter 关于如何创建Visual 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
,然后将其添加到列表中。此后,我正在尝试为此创建控件。这太乱了,我还没有完全实现我的目标。但我觉得我不会对最终结果感到满意。如果你能提出一种方法来实现同样的目标,那将会有很大的帮助。感谢。
取自
的样本答案 0 :(得分:1)
所以,这当然是可能的。您需要做的是定义反序列化例程以生成实现List<T>/ObservableCollection<T>
的{{1}}个对象。您可以通过INotifyPropeertyChanged
执行此操作,也可以将Newtonsoft Json
写入JSchema
转换器
接下来,您可以将ViewModel
甚至ContentControl
绑定到此可枚举,如主详细信息视图,并且详细信息视图可以在所选对象上实现Listbox/StackPanel
。 Example of Property grid
确保所有绑定均为Property Grid
,以保留您所做的更改。
此外,您可以在TwoWay
上实施OnSelectionChanged
事件以序列化更改。
答案 1 :(得分:0)
我想为UWP做同样的事情,但是没有找到可以使用的可行解决方案。 除了上面提到的PropertyGrid,我还发现 Windows社区工具包中的DataGrid和Telerik中的DataForm。 仍然使用这些将需要将Json转换为Object模型然后返回。 事实证明,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;
}
}
}