我有一个XML文件存储在数据库中作为XML格式,其中包含一些控件,如下拉文本框,标签文本区域等,可能有也可能没有初始值。所以我的目标是读取XML文件并基于控件类型,我需要动态创建该控件并关联初始值(如果有的话)并且必须在视图中显示页面的预览。任何人请帮助我如何在MVC 3中为此方案动态创建控件。
例如:我的xml文件看起来像这样。
<?xml version="1.0" encoding="utf-8" ?>
<controls>
<control>
<type name="label">
<property name="Visible" value="true"/>
<property name="ID" value="Label1"/>
.
.
.
</type>
</control>
<control>
<type name="TextBox">
<property name="Visible" value="true"/>
<property name="ID" value="TextBox1"/>
.
.
.
</type>
</control>
.
.
.
</controls>
提前致谢。
答案 0 :(得分:49)
我会尝试为您提供一些可能会给您一些想法的提示。
与往常一样,我们首先定义一个代表UI的视图模型:
public class MyViewModel
{
public ControlViewModel[] Controls { get; set; }
}
public abstract class ControlViewModel
{
public abstract string Type { get; }
public bool Visible { get; set; }
public string Label { get; set; }
public string Name { get; set; }
}
public class TextBoxViewModel : ControlViewModel
{
public override string Type
{
get { return "textbox"; }
}
public string Value { get; set; }
}
public class CheckBoxViewModel : ControlViewModel
{
public override string Type
{
get { return "checkbox"; }
}
public bool Value { get; set; }
}
public class DropDownListViewModel : TextBoxViewModel
{
public override string Type
{
get { return "ddl"; }
}
public SelectList Values { get; set; }
}
因此,我们已经定义了一些我们希望在应用程序中处理的基本控件。下一步将是一个存储库方法,它将查询数据库,获取XML,然后是一个映射层,最终将为我们提供视图模型的实例。我将此视为超出此答案的范围,因为有许多方法可以实现它(XmlSerializer,XDocument,XmlReader,...)。
我想你已经有了一个视图模型的实例。像这样:
public ActionResult Index()
{
var model = new MyViewModel
{
Controls = new ControlViewModel[]
{
new TextBoxViewModel
{
Visible = true,
Label = "label 1",
Name = "TextBox1",
Value = "value of textbox"
},
new CheckBoxViewModel
{
Visible = true,
Label = "check label",
Name = "CheckBox1",
Value = true
},
new DropDownListViewModel
{
Visible = true,
Label = "drop label",
Name = "DropDown1",
Values = new SelectList(
new[]
{
new { Value = "1", Text = "text 1" },
new { Value = "2", Text = "text 2" },
new { Value = "3", Text = "text 3" },
}, "Value", "Text", "2"
)
}
}
};
return View(model);
}
所以我已经硬编码了一些值来说明这个概念,但是一旦你实现了存储库和映射层,通常这个控制器动作看起来像这样:
public ActionResult Index()
{
string xml = _repository.GetControls();
var model = Mapper.Map<string, MyViewModel>(xml);
return View(model);
}
好的,现在让我们转到相应的Index.cshtml
视图,其中包含以下格式:
@model MyViewModel
@using (Html.BeginForm())
{
for (int i = 0; i < Model.Controls.Length; i++)
{
if (Model.Controls[i].Visible)
{
<div>
@Html.HiddenFor(x => x.Controls[i].Type)
@Html.HiddenFor(x => x.Controls[i].Name)
@Html.EditorFor(x => x.Controls[i])
</div>
}
}
<input type="submit" value="OK" />
}
好的,现在我们可以为我们想要处理的控件定义相应的编辑器模板:
~/Views/Shared/EditorTemplates/TextBoxViewModel.cshtml
@model AppName.Models.TextBoxViewModel
@Html.LabelFor(x => x.Value, Model.Label)
@Html.TextBoxFor(x => x.Value)
~/Views/Shared/EditorTemplates/CheckBoxViewModel.cshtml
@model AppName.Models.CheckBoxViewModel
@Html.CheckBoxFor(x => x.Value)
@Html.LabelFor(x => x.Value, Model.Label)
~/Views/Shared/EditorTemplates/DropDownListViewModel.cshtml
@model AppName.Models.DropDownListViewModel
@Html.LabelFor(x => x.Value, Model.Label)
@Html.DropDownListFor(x => x.Value, Model.Values)
到目前为止,这么好。在此阶段,您应该能够呈现包含动态控件的表单。但是当然这样的形式对任何人来说都是无用的。什么是好的是有可能POST这个表单并捕获用户在控制器操作中输入的值,以便我们可以处理它们。
控制器操作如下所示:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
... process the values
}
现在这样会很好但当然它不会起作用,因为ControlViewModel
视图模型是一个抽象类,默认模型绑定器不知道要实例化哪个特定实现。所以我们需要帮助他=&gt;通过编写自定义模型绑定器:
public class ControlModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var type = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type");
object model = null;
switch (type.AttemptedValue)
{
case "textbox":
{
model = new TextBoxViewModel();
break;
}
case "checkbox":
{
model = new CheckBoxViewModel();
break;
}
case "ddl":
{
model = new DropDownListViewModel();
break;
}
default:
{
throw new NotImplementedException();
}
};
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
return model;
}
}
将在Application_Start
中注册并与ControlViewModel
类型相关联):
ModelBinders.Binders.Add(typeof(ControlViewModel), new ControlModelBinder());
答案 1 :(得分:0)
事实上似乎很简单。从数据库中获取XML,解析它并将其放入某些模型类中。那些分类将包含控制数据。
接下来创建部分视图,它将根据模型动态构建所需的控件。
最后,从jQuery ajax调用该操作并将返回的HTML放在适当的位置。
快速,简单,没有真实......
答案 2 :(得分:0)
你可以将模型传递给强类型视图,并在帮助程序中编写一个名为Html.ControlFor的html帮助程序,你可以读取xml文件并根据属性名称的匹配创建控件(输入,选择等)(其中属性名称)匹配xml文件中的属性标记)