我一直在努力寻找解决方案,以解决我正在忙于设计的情况,但是我没有设法解决。
想象一下下面的模型
public enum InputType
{
TextInput,
LookupInput
}
public struct AdditionalProperty
{
public string Key {get;set;}
public string Value {get;set;}
public InputType Type {get;set;}
}
public class Person
{
public string FirstName {get;set;}
public List<AdditionalProperty> AdditionalProperties {get;set;}
}
然后,具有以下控制器
public class HomeController
{
public ActionResult Index()
{
var model = new Person { FirstName = "MyName" };
model.AdditionalProperties = new List<AdditionalProperty>();
var listItem = new AdditionalProperty
{
Key = "Surname",
Value = "MySurname"
};
model.AdditionalProperties.Add(listItem);
return View(model)
}
}
我要寻找的是Razor视图代码,该代码如何“动态”创建具有正确输入类型的属性,并绑定到某些东西上,以便在表单回发后仍能够使用模型到控制器以获取保存功能。
因此已知的属性将如下所示:
<div class="form-group">
<div class="form-row">
<div class="col-md-6">
@Html.LabelFor(model => model.FirstName, new { @class = "control-label" })
<div>
@Html.TextBoxFor(model => model.FirstName, new { @class = "form-control", placeholder = "Enter Group Name", type = "text" })
@Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
</div>
</div>
</div>
</div>
随后的想法是拥有以下内容。显然,下面的内容还不够,这是我需要帮助的地方。 我想显示其他属性,一个在另一个之下,每个基于属性在单独的行上(使用引导行)。InputType
@foreach (var property in Model.Properties)
{
@Html.LabelFor(model => property.Key, new { @class = "control-label" })
<div>
@if (property.InputType == TextInput)
{
@Html.TextBoxFor(model => property.Value, new { @class = "form-control", placeholder = "Enter Group Name", type = "text" })
}
@Html.ValidationMessageFor(model => property.Key, "", new { @class = "text-danger" })
</div>
}
因此,我希望将我的视图显示为:
| <label> | <input>
Known Property | FirstName | MyFirstName
Unknown Property | Surname | MySurname
答案 0 :(得分:0)
关于完整性,我将发布以下答案。
我将发布模型,视图(索引和EditorTemplates)和控制器,以显示用于测试给出的答案的完整的工作解决方案。
此测试的“我的模型”类
Person.cs
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<AdditionalProperty> AdditionalProperties { get; set; }
}
AdditionalProperty.cs
public struct AdditionalProperty
{
public string Key { get; set; }
public object Value { get; set; }
public DateTime? DateValue
{
get
{
DateTime dateValue;
if (DateTime.TryParse(Value?.ToString(), out dateValue))
{
return dateValue;
}
return null;
}
set => Value = value;
}
public InputType InputType { get; set; }
public List<SelectListItem> ValueLookupItems { get; set; }
}
我在这里具有单独的DateValue属性的原因是,在进行DateTime绑定时可以帮助浏览器,否则DateTimePicker不会显示。
我使用一个枚举来确定此特定属性应使用的输入类型。
InputType.cs
public enum InputType
{
TextBox,
DropdownBox,
TextArea,
DateSelection,
}
为了使视图尽可能简单,Stephen为我提供了索引视图的示例以及AdditionalProperty对象的EditorTemplate。 EditorTemplate用于分离关注点,并确保使用哪种输入类型背后的所有逻辑都在一个地方。
我发现DateTime属性不能很好地工作,因此需要一个附加的EditorTemplate。我是从this post那里得到的。
DateTime.cshtml
注意:模板的位置-> / Views / Shared / EditorTemplates
@model DateTime
@{
IDictionary<string, object> htmlAttributes;
object objAttributes;
if (ViewData.TryGetValue("htmlAttributes", out objAttributes))
{
htmlAttributes = objAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(objAttributes);
}
else
{
htmlAttributes = new RouteValueDictionary();
}
htmlAttributes.Add("type", "date");
String format = (Request.UserAgent != null && Request.UserAgent.Contains("Chrome")) ? "{0:yyyy-MM-dd}" : "{0:d}";
@Html.TextBox("", Model, format, htmlAttributes)
}
AdditionalProperty.cshtml
注意:模板的位置-> / Views / Shared / EditorTemplates
注意:我的AdditionalProperty的位置是DynamicViewExample.Models命名空间的一部分
@model DynamicViewExample.Models.AdditionalProperty
<div>
@Html.HiddenFor(m => m.Key)
@Html.LabelFor(m => m.Key, Model.Key, new {@class = "control-label"})
@if (Model.InputType == DynamicViewExample.Models.InputType.TextBox)
{
@Html.TextBoxFor(m => m.Value, new {@class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.TextArea)
{
@Html.TextAreaFor(m => m.Value, new {@class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.DropdownBox)
{
@Html.DropDownListFor(m => m.Value, Model.ValueLookupItems, new {@class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.DateSelection)
{
@Html.EditorFor(m => m.DateValue, new {@class = "form-control"})
}
else
{
@Html.HiddenFor(m => m.Value) // we need this just in case
}
</div
这就是 Index.cshtml 文件的外观
@model DynamicViewExample.Models.Person
@{
ViewBag.Title = "Home Page";
}
@using (Html.BeginForm())
{
<div class="row">
@Html.LabelFor(model => model.FirstName, new { @class = "control-label" })
@Html.TextBoxFor(model => model.FirstName, new { @class = "form-control", placeholder = "Enter Group Name", type = "text" })
@Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
</div>
<div class="row">
@Html.LabelFor(model => model.LastName, new { @class = "control-label" })
@Html.TextBoxFor(model => model.LastName, new { @class = "form-control", placeholder = "Enter Group Name", type = "text" })
@Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
</div>
<div class="row">
@Html.EditorFor(m => m.AdditionalProperties, new { htmlAttributes = new { @class = "form-control"}})
</div>
<input type="submit" class="btn btn-primary" />
}
最后, HomeController.cs 文件包含一个Get and Post(获取和发布),该文件可以根据需要操纵数据。这里缺少的是填充模型的“动态”方式,但是一旦将DB引入混合中,自然就会发生这种情况。
[HttpGet]
public ActionResult Index()
{
var model = new Person
{
FirstName = "Gawie",
LastName = "Schneider",
AdditionalProperties = new List<AdditionalProperty>
{
new AdditionalProperty {Key = "Identification Number", Value = "1234567890123456", InputType = InputType.TextBox},
new AdditionalProperty {Key = "Date Of Birth", Value = DateTime.Today, InputType = InputType.DateSelection},
new AdditionalProperty {Key = "Age", Value = "31", InputType = InputType.TextBox},
new AdditionalProperty {Key = "Gender", Value = "Male", InputType = InputType.DropdownBox,
ValueLookupItems = new List<SelectListItem>
{
new SelectListItem{Text = "Male", Value = "Male"},
new SelectListItem{Text = "Female", Value = "Female"}
}},
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Person model)
{
//Do some stuff here with the model like writing it to a DB perhaps
return RedirectToAction("Index");
}
因此,如果我必须总结一下我在这里试图做的事情。
我想要实现的目标是能够将强类型/已知属性与动态/未知属性结合使用,以创建一个系统,该系统允许用户即时创建新输入而无需开发人员参与其中。
老实说,我希望有一天也能对别人有所帮助。
享受编码经验
高威