用于动态视图数据/表单的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。
希望这可以帮助。