gpt4 book ai didi

asp.net - 使用OptGroup组构造选择列表

转载 作者:行者123 更新时间:2023-12-02 06:10:20 25 4
gpt4 key购买 nike

当前的项目:


ASP.NET 4.5.2
MVC 5


我正在尝试使用Model中的OptGroups构建选择菜单,但是我的问题是我似乎无法自行构建OptGroups

我的模特:

[DisplayName("City")]
public string CityId { get; set; }
private IList<SelectListItem> _CityName;
public IList<SelectListItem> CityName {
get {
List<SelectListItem> list = new List<SelectListItem>();
Dictionary<Guid, SelectListGroup> groups = new Dictionary<Guid, SelectListGroup>();
List<Region> region = db.Region.Where(x => x.Active == true).OrderBy(x => x.RegionName).ToList();
foreach(Region item in region) {
groups.Add(item.RegionId, new SelectListGroup() { Name = item.RegionName });
}
List<City> city = db.City.Where(x => x.Active == true).ToList();
foreach(City item in city) {
list.Add(new SelectListItem() { Text = item.CityName, Value = item.CityId.ToString(), Group = groups[item.RegionId] });
}
return list;
}
set { _CityName = value; }
}


每个城市可以在一个区域中。我想要一个选择菜单,按地区对城市进行分组。据我所知,上面的代码应该可以完成这项工作,但是我得到一个下拉菜单,其中所有城市分组在名为 System.Web.Mvc.SelectListGroup的OptGroup下

上面代码中的关键是,我首先遍历Regions,然后将它们放入Dictionary中,将 RegionId设置为带回 RegionName的键(其本身被格式化为SelectListGroup)。

然后,我遍历各个城市,并将与城市 RegionId相匹配的组分配给每个城市。

我没有在Internet上看到任何实际从数据库中提取内容的示例-所有示例中的100%使用硬编码的 SelectListGroupSelectListItem值。

我的观点也是正确的,AFAIK:

@Html.DropDownListFor(x => x.CityId, new SelectList(Model.CityName, "Value", "Text", "Group", 1), "« ‹ Select › »", htmlAttributes: new { @class = "form-control" })


如您所见,应该将Group放入 SelectList,并且 DropDownList是用 OptGroups创建的,而不是正确的。

我得到的下拉菜单如下所示:

« ‹ Select › »
System.Web.Mvc.SelectListGroup
City1
City2
...
LastCity


什么时候应该是这样的:

« ‹ Select › »
Region1
City2
City4
City5
Region2
City3
City1
City6


有什么建议吗?



修改后的解决方案:我遵循了 the solution提供的 Stephen Muecke,但对其做了一些修改。

MVC的一般规则之一是您拥有一个比控制器重的模型,并且该模型定义了您的业务逻辑。 Stephen断言所有数据库访问都应在控制器中完成。我已经同意了两者。

我最大的“问题”之一是,每次调用页面时,都需要调用下拉菜单或任何其他预填充表单元素的创建。这意味着,对于创建或编辑页面,不仅需要在[HttpGet]方法上调用它,而且还需要在[HttpPost]方法上调用它,因为模型没有正确验证,因此模型被发送回视图。这意味着您必须向每个方法中添加代码(通常通过ViewBags),只是为了预先填充诸如下拉列表之类的元素。这被称为代码复制,不是一件好事。必须有一种更好的方法,并且在斯蒂芬的指导下,我找到了一个方法。

将数据访问权限限制在模型之外的问题是,您需要用数据填充模型。避免代码重用和避免潜在错误的问题是,您不应该将数据绑定到控制器中的元素。后一个动作是业务逻辑,并且正确地属于模型。在我的情况下,业务逻辑是我需要将用户输入限制为按区域分组的城市列表,管理员可以从下拉列表中进行选择。因此,尽管我们可以在控制器中组装数据,但仍将其绑定到模型中的模型。我之前的错误是在模型中同时进行,这是完全不合适的。

通过将数据绑定到模型中的模型,我们避免了必须将其绑定两次-在控制器的[HttpGet]和[HttpPost]方法中每个都绑定一次。在这两种方法都处理的模型中,我们只需绑定一次即可。而且,如果我们有一个可以在Create和Edit函数之间共享的更通用的模型,那么我们只能在一个位置而不是四个位置进行这种绑定(但是我没有这种通用性,因此我不会给出一个例子)

因此,首先,我们实际上剥离了整个数据组装,并将其粘贴在自己的类中:

public class SelectLists {
public static IEnumerable<SelectListItem> CityNameList() {
ApplicationDbContext db = new ApplicationDbContext();
List<City> items = db.City.Where(x => x.Active == true).OrderBy(x => x.Region.RegionName).ThenBy(x => x.CityName).ToList();
return new SelectList(items, "CityId", "CityName", "Region.RegionName", 1);
}
}


它存在于名称空间中,但在我们要处理的部分的控制器之下。为了清楚起见,我将其粘贴在文件的最后,就在命名空间关闭之前。

然后我们看一下该页面的模型:

public string CityId { get; set; }
private IEnumerable<SelectListItem> _CityName;
public IEnumerable<SelectListItem> CityName {
get { return SelectLists.CityNameList(); }
set { _CityName = value; }
}


注意:即使 CityIdGuid,而DB字段是 uniqueidentifier,但由于客户端验证会吸收Guid的驴球,因此我将该值作为字符串通过视图引入。如果 Value是字符串而不是Guid,则在下拉菜单上进行客户端验证要容易得多。您只需将其转换回Guid,然后再将其插入该表的主模型。另外,CityName不是“城市”表中的实际字段-它纯粹作为下拉菜单本身的占位符存在,这就是为什么它存在于“创建”页面的 CreateClientViewModel中。这样,在视图中,我们可以创建一个 DropDownListFor,将 明确绑定到下拉菜单,实际上首先允许客户端验证(Guid只是增加了麻烦)。

关键是 get {}。如您所见,不再需要进行数据库访问的大量代码,只需一个针对类的简单 SelectLists以及方法 CityNameList()的调用即可。您甚至可以将变量传递给该方法,因此可以使同一方法带回同一下拉菜单的不同变体。说,如果您希望在一个页面上的一个下拉列表(创建)将其选项按OptGroups分组,而在另一个下拉列表(编辑)中不包含任何选项分组。

实际模型最终变得比以前更简单:

@Html.DropDownListFor(x => x.CityId, Model.CityName, "« ‹ Select › »", htmlAttributes: new { @class = "form-control" })


无需修改引入下拉列表数据的元素,只需通过 Model.ElementName进行调用。

我希望这有帮助。

最佳答案

首先,您查看的模型不应包含用于填充其属性的数据库访问代码。这是控制器的责任,您使代码无法进行单元测试。首先将模型更改为

public class CreateClientViewModel
{
[DisplayName("City")]
public string CityId { get; set; }
public IList<SelectListItem> CityList { get; set; }
....
}


然后在控制器中,可以使用接受 SelectListgroupName重载之一来生成集合

var cities = var cities = db.City.Include(x => x.Region).Where(x => x.Active == true)
.OrderBy(x => x.Region.RegionName).ThenBy(x => x.CityName);

var model = new CreateClientViewModel()
{
CityList = new SelectList(cities, "CityId", "CityName", "Region.RegionName", null, null)
};
return View(model);


并认为

@Html.DropDownListFor(x => x.CityId, Model.CityList , "« ‹ Select › »", new { @class = "form-control" })


或者,您也可以使用 GroupSelectListItem属性执行此操作。

var model = new CreateClientViewModel()
{
CityList = new List<SelectListItem> // or initialize this in the constructor
};
var cities = var cities = db.City.Include(x => x.Region).Where(x => x.Active == true).GroupBy(x => x.Region.RegionName);
foreach(var regionGroup in cities)
{
var optionGroup = new SelectListGroup() { Name = regionGroup.Key };
foreach(var city in regionGroup)
{
model.CityList.Add(new SelectListItem() { Value = city.CityId.ToString(), Text = city.CityName, Group = optionGroup });
}
}
return View(model);

关于asp.net - 使用OptGroup组构造选择列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37151572/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com