用于动态视图数据/表单的ASP.Net MVC编辑器模板

我正在实现一个MVC3 / Razor Web应用程序,它可以检索用户可以从其他服务编辑的一些“字段”,因此在视图中编辑的属性列表在编译时是完全动态的和未知的。

我编写了一些部分视图和HTML帮助程序,它们遍历从其他服务检索到的组和属性。 现在,我必须为各种属性类型构建标记,并考虑为什么不重新使用MVC编辑器模板系统呢? 支持各种数据类型(例如复选框等),甚至可以使用我的自定义模板对其进行自定义。

到目前为止这么好但我如何使用Html.EditorFor()Html.Editor()来获取自定义数据对象/属性? 构建动态表单而不使用静态类型数据作为视图模型的含义。

这是我的HTML帮助程序代码的简约示例:

 public static MvcHtmlString GetField(this HtmlHelper helper, Field field) { ... return helper.EditorFor(field, m => m.Value); ... } 

属性“field”是我从外部服务获得的字段。 它具有object类型的“Value”属性。 我喜欢为这个属性类型构建编辑器代码。

据我所知,编辑器模板是基于当前的视图模型构建的。 我可以将另一个对象作为模型传递给当前视图模型(例如,在上面的示例“field”中)?

任何帮助都会很棒!

干杯,马克

我的第一个ASP MVC任务涉及构建一个动态表单,并不是直截了当的。
基本上你不能使用内置的助手或validation,因为他们期望强类型的对象。

我的视图基本上遍历输入字段,检查DataType(bool,int,string,datetime等)并直接为该类型构建编辑器。

您还必须手动执行所有validation,使用属性修饰类型以执行此操作不起作用,请参阅我的问题if(ModelState.IsValid)是否与FormsCollection不兼容。 用什么代替?

Razor View逻辑(我们使用DevExpress MVC扩展,但你得到漂移)
表单对象及其Fields集合是我们的定制对象,描述了表单的外观(页面收集搜索条件,这就是您在代码中看到条件和搜索类型名称的原因)。

  @foreach (var field in form.Fields) {  @if (field.IsVisible) {  }  } 
@Html.DevExpress().Label(s => s.Text = field.Caption).GetHtml() @if (field.Type == typeof(bool)) { @Html.CheckBox(s => { s.Checked = field.IsBoolSet; s.Name = field.Name; s.ClientEnabled = !field.IsReadonly; }).GetHtml() } else if (field.Type == typeof(DateTime)) { Html.DevExpress().DateEdit(s => { s.Name = field.Name; s.ClientEnabled = !field.IsReadonly; if (!string.IsNullOrEmpty(field.Value)) { DateTime dateValue; if (DateTime.TryParse(field.Value, out dateValue)) s.Date = dateValue; } }).GetHtml(); } else if (field.ListValues.Count > 0) { Html.DevExpress().ListBox(s => { s.Name = field.Name; s.ClientVisible = field.IsVisible; s.ClientEnabled = !field.IsReadonly; s.Properties.SelectionMode = DevExpress.Web.ASPxEditors.ListEditSelectionMode.CheckColumn; s.Properties.TextField = "Name"; s.Properties.ValueField = "Value"; s.Properties.ValueType = typeof(string); //s.Properties.EnableClientSideAPI = true; foreach (var item in field.ListValues) { s.Properties.Items.Add(item.Name, item.Value); } //s.Properties.ClientSideEvents.SelectedIndexChanged = "MultiSelectListChanged"; s.Properties.ClientSideEvents.Init = "MultiSelectListInit"; }).GetHtml(); } else { //Html.TextBox(field.Name, field.Value) Html.DevExpress().TextBox(s => { s.Name = field.Name; s.Text = field.Value; }).GetHtml(); } @Html.ValidationMessage(field.Name) @Html.DevExpress().CheckBox(s => { s.Checked = field.IncludeInSearch; s.Name = "use_" + field.Name; s.ClientEnabled = (!field.IsMandatory); }).GetHtml()

Controller操作接受Forms Collection。 我遍历formsCollection,寻找我在视图中指定的控件名称。

 [HttpPost] public ActionResult QueryCriteria(FormCollection formCollection) { var isValid = true; foreach (var field in form.Fields) { var value = (formCollection[field.Name] ?? "").Trim(); ... 

如果存在任何validation错误,我可以通过将ModelError直接添加到模型来指定控制级别validation,例如

 ModelState.AddModelError(field.Name, "This is a mandatory field"); 

如果有validation错误,我会返回View。

希望这可以帮助。