我有一个XML文件作为XML格式存储在数据库中,其中包含一些控件,如下拉文本框,标签文本区域等,可能有初始值,也可能没有初始值。因此,我的目标是读取XML文件,并且基于控件类型,我需要动态创建该控件并关联初始值(如果有的话),并且必须在视图中显示页面的预览。任何人,请帮助我如何在MVC3中为这个场景动态创建控件。
例如:我的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>
提前谢谢。
发布于 2011-06-13 17:26:14
我会试着为你提供一些提示,可能会给你一些想法。
像往常一样,让我们从定义一个表示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 =>
@model AppName.Models.CheckBoxViewModel @Html.CheckBoxFor(x => x.Value) @Html.LabelFor(x => x.Value,模型
@model AppName.Models.DropDownListViewModel @Html.LabelFor(x => x.Value,Model.Label) @Html.DropDownListFor(x => x.Value,Model.Label
到现在为止还好。在此阶段,您应该能够呈现包含动态控件的窗体。当然,这样的表单对任何人来说都是非常无用的。更好的是可以对这个表单执行POSTing操作,并捕获用户在控制器操作中输入的值,这样我们就可以处理它们了。
控制器操作将如下所示:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
... process the values
}
现在这样做很好,但当然不会起作用,因为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;
}
}
它将在Application_Start
中注册并与ControlViewModel
类型关联):
ModelBinders.Binders.Add(typeof(ControlViewModel), new ControlModelBinder());
发布于 2011-06-13 11:26:39
事实上,这看起来很简单。从数据库获取XML,对其进行解析并将其放入一些模型类中。这些类将包含控件数据。
接下来,创建局部视图,该视图将根据模型动态构建所需的控件。
最后,从HTML调用该操作,并将返回的jQuery放在适当的位置。
快点,简单点,不用再装了.
发布于 2011-06-13 12:40:19
您可以将一个模型传递给您的强类型视图,并在该助手中编写一个名为Html.ControlFor的html助手。您可以读取xml文件并创建控件(输入、选择等)。基于属性名称的匹配(其中属性名称与xml文件中的属性标签匹配)
https://stackoverflow.com/questions/6329461
复制相似问题