Bon*_*viD 28 asp.net-mvc asp.net-mvc-3
我有一个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>
Run Code Online (Sandbox Code Playgroud)
提前致谢.
Dar*_*rov 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; }
}
Run Code Online (Sandbox Code Playgroud)
因此,我们已经定义了一些我们希望在应用程序中处理的基本控件.下一步将是一个存储库方法,它将查询数据库,获取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);
}
Run Code Online (Sandbox Code Playgroud)
所以我已经硬编码了一些值来说明这个概念,但是一旦你实现了存储库和映射层,通常这个控制器动作看起来像这样:
public ActionResult Index()
{
string xml = _repository.GetControls();
var model = Mapper.Map<string, MyViewModel>(xml);
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
好的,现在让我们移动到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" />
}
Run Code Online (Sandbox Code Playgroud)
好的,现在我们可以为我们想要处理的控件定义相应的编辑器模板:
~/Views/Shared/EditorTemplates/TextBoxViewModel.cshtml
@model AppName.Models.TextBoxViewModel
@Html.LabelFor(x => x.Value, Model.Label)
@Html.TextBoxFor(x => x.Value)
Run Code Online (Sandbox Code Playgroud)~/Views/Shared/EditorTemplates/CheckBoxViewModel.cshtml
@model AppName.Models.CheckBoxViewModel
@Html.CheckBoxFor(x => x.Value)
@Html.LabelFor(x => x.Value, Model.Label)
Run Code Online (Sandbox Code Playgroud)~/Views/Shared/EditorTemplates/DropDownListViewModel.cshtml
@model AppName.Models.DropDownListViewModel
@Html.LabelFor(x => x.Value, Model.Label)
@Html.DropDownListFor(x => x.Value, Model.Values)
Run Code Online (Sandbox Code Playgroud)到现在为止还挺好.在此阶段,您应该能够呈现包含动态控件的表单.但是当然这样的形式对任何人来说都是无用的.什么是好的是有可能POST这个表单并捕获用户在控制器操作中输入的值,以便我们可以处理它们.
控制器操作如下所示:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
... process the values
}
Run Code Online (Sandbox Code Playgroud)
现在这很好但当然它不会工作,因为ControlViewModel
视图模型是一个抽象类,默认模型绑定器不知道要实例化哪个特定实现.所以我们需要通过编写自定义模型绑定器帮助他=>:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
将在Application_Start
该ControlViewModel
类型中注册并与之关联):
ModelBinders.Binders.Add(typeof(ControlViewModel), new ControlModelBinder());
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
38317 次 |
最近记录: |