Моя первая задача ASP MVC заключалась в создании динамической формы, и она не проста.
По сути, вы не можете использовать встроенные помощники или проверки, потому что они ожидают строго типизированных объектов.
Мое представление в основном перебирает поля ввода, проверяет тип данных (bool, int, string, datetime и т. Д.) И создает редактор непосредственно для этого типа.
Вы также должны выполнить всю свою проверку вручную, с украшением типов атрибутами, чтобы это не сработало, см. Мой вопрос , если (ModelState.IsValid) не работает с FormsCollection. Что использовать вместо?
Razor View logic (мы используем расширения DevExpress MVC, но вы получаете дрейф)
Объект формы и его коллекция Fields являются нашими объектами на заказ, которые описывают, как должна выглядеть форма (на странице собраны критерии поиска, поэтому в коде вы увидите критерии и имена типов поиска).
<table id="criteriaTable">
@foreach (var field in form.Fields)
{
<tr id="criteriaTableRow">
@if (field.IsVisible)
{
<td id="criteriaTableLabelCol">
@Html.DevExpress().Label(s => s.Text = field.Caption).GetHtml()
</td>
<td id="criteriaTableEditCol">
@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)
{
<input type="hidden" id="@("initiallySelected" + field.Name)" value="@field.Value" />
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)
<input type="hidden" name="@("oldvalue_" + field.Name)" value="@field.Value" />
<input type="hidden" name="@("olduse_" + field.Name)" value="@(field.IncludeInSearch ? "C" : "U")" />
</td>
<td id="criteriaTableIncludeCol">
@Html.DevExpress().CheckBox(s =>
{
s.Checked = field.IncludeInSearch;
s.Name = "use_" + field.Name;
s.ClientEnabled = (!field.IsMandatory);
}).GetHtml()
</td>
}
</tr>
}
</table>
Действие Controller принимает коллекцию форм. Я перебираю formCollection в поисках имен элементов управления, указанных в представлении.
[HttpPost]
public ActionResult QueryCriteria(FormCollection formCollection)
{
var isValid = true;
foreach (var field in form.Fields)
{
var value = (formCollection[field.Name] ?? "").Trim();
...
Если есть какие-либо ошибки проверки, я могу указать проверку уровня управления, добавив ModelError непосредственно в модель, например.
ModelState.AddModelError(field.Name, "This is a mandatory field");
и я возвращаю вид, если есть ошибки проверки.
Надеюсь, это поможет.