如何将下拉列表绑定到 ASP.Net MVC C# 中动态生成的变量
本文关键字:动态 变量 MVC Net 下拉列表 绑定 ASP | 更新日期: 2023-09-27 18:31:53
我们有一个应用程序,它使用动态自定义属性来定义系统中某些实体的属性/属性。
因此,在某些情况下,我们需要动态填充表单字段(通常是下拉列表或复选框列表),理想情况下是在视图中指定自定义属性类型。
这个问题专门针对下拉列表。
这就是我们正在努力做的事情:
视图模型:
public class SearchViewModel
{
#region Properties
public Dictionary<string, SelectList> CustomPropertySelectLists { get; set; }
public Dictionary<string, string> SelectedCustomProperties { get; set; }
#endregion
#region Constructors
public SearchViewModel()
{
//Create the SelectedCustomProperties list and pre-populate with a blank item for each CustomPropertyType
SelectedCustomProperties = new Dictionary<string, string>();
foreach (CustomPropertyType cpt in Core.GetCustomPropertyTypes())
{
SelectedCustomProperties.Add(cpt.CustomPropertyTypeId, string.Empty);
}
}
#endregion
}
控制器:
public ActionResult Search(int searchId)
{
var svm = new SearchViewModel();
//Load selected custom property ids for this search
if ( searchId > 0 )
{
Search s = Core.GetSearch(searchId);
foreach ( CustomPropertyType cpt in Core.GetCustomPropertyTypes()) )
{
int cpid = s.GetBasicSearchCustomPropertyId(cpt.CustomPropertyTypeId);
if ( cpid > 0 )
{
//NB assumes entries already present (i.e. were created in the constructor)
svm.SelectedCustomProperties[cpt.CustomPropertyTypeId] = cpid.ToString();
}
}
}
//Load lists of all custom property select lists so the view can just dynamically use whichever ones it wants
svm.CustomPropertySelectLists = Core.GetSelectListsForAllCustomPropertyTypes();
return View(svm);
}
然后在视图中:
@using (Html.BeginForm())
{
<fieldset>
<div class="row">
<div class="col">
@Html.DropDownListFor(m => m.SelectedCustomProperties["Sector"], Model.CustomPropertySelectLists["Sector"], "Sector", new { @class = "browser-default" })
</div>
<div class="col">
@Html.DropDownListFor(m => m.SelectedCustomProperties["Location"], Model.CustomPropertySelectLists["Location"], "Location", new { @class = "browser-default" })
</div>
</div>
</fieldset>
}
这一切都适用于填充动态定义的下拉列表。 我们甚至可以通过循环访问自定义属性类型来动态定义要在运行时呈现的下拉列表,这些自定义属性类型已定义为出现在系统的某些部分和/或使用存储在系统中其他位置的配置的某些实体。
但是,下拉列表的选定值没有被选取,大概是因为它试图绑定到类似 m => m.SelectedCustomProperties["Sector"]
的东西,而不是标量变量属性。
我意识到在我们的视图模型中,我们可以有这样的东西:
public string SelectedCustomPropertyIdSector { get; set; }
然后在控制器中填充SelectedCustomPropertyIdSector
,然后使用 m => m.SelectedCustomPropertyIdSector
绑定到下拉列表,但这会在一定程度上破坏系统中自定义属性的动态性质,因为我们必须根据使用情况将属性硬编码到 ViewModel/控制器。
理想情况下,我们希望能够编写通用的、可重用的模型和控制器代码,这些代码只与数据库中的"CustomProperty"实体有关,然后通过引用视图标记中的自定义属性类型 ID(和/或通过动态决定在运行时呈现的下拉列表)让视图指定要使用的特定自定义属性。
只有当我们可以让 DropDownListFor 属性绑定到动态生成的列表(由自定义属性类型 id 引用)中的某些内容而不是通常的缩放器变量时,这才有可能,但这似乎是不可能的?
我对 MVC 比较陌生,但根据我的经验,下拉列表想要更新视图模型的一个众所周知的属性,即您提到的标量 SelectedCustomPropertyIdSector。
您是否尝试过将 SelectedCustomProperties 作为 HiddenFor 包含以确保列表本身在发布后返回到操作?
它可能不起作用,因为视图模型在呈现页面后不记得列表,并且没有标量变量附加到该列表可能是问题所在。
看起来模型绑定有问题。在发布模型时,无法将呈现的 Html 绑定回模型中。
你可能想看看这篇博文 http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
我自己没有将项目绑定到字典,但必须绑定到IEnumerable<Object>
.您可以尝试创建CustomPropertyViewModel
public class CustomPropertyViewModel
{
public string Filter { get; set; }
public string SelectedValue { get; set; }
public SelectList SelectList { get; set; }
}
您的SearchViewModel
将包含
IEnumerable<CustomerPropertyViewModel> CustomProperties { get; set; }
你会在视图中呈现类似的东西
@for (int i = 0; i < Model.CustomPropeties.Count(); i++)
{
@Html.HiddenFor(x => Model.CustomProperties[i].Filter
@Html.DropdownListFor(x => Model.CustomProperties[i].SelectedValue,
Model.CustomProperties[i].SelectList)
}
尝试使用@Html.DropDownList
帮助程序而不是@Html.DropDownListFor
@Html.DropDownList("Sector", Model.CustomPropertySelectLists["Sector"], "Sector", new { @class = "browser-default" })
这样,提交的值将在回发操作中作为Request.Form["Sector"]
然后,您需要将其映射到您的属性。所以这样的事情应该可以工作(我假设你可以自动编写一些代码,因为你有你的自定义属性名称):
SelectedCustomProperties["Sector"] = Request.Form["Sector"]
编辑 您可以自动生成下拉列表和顺序模型绑定:
@for(var key in Model.CustomPropertySelectLists.Keys)
{
@Html.DropDownList(key , Model.CustomPropertySelectLists[key], key , new { @class = "browser-default" })
}
在回发操作中:
var types = Core.GetCustomPropertyTypes()
foreach(var t in types)
{
if(Request.Form.ContainsKey(t.CustomPropertyTypeId))
{
SelectedCustomProperties[t.CustomPropertyTypeId] = Request.Form[t.CustomPropertyTypeId]
}
}