要点:
我正在尝试使用两个DropDownList控件来过滤当前正在视图中排序和显示的数据。
我们将要学习的内容 创建可以使用DropDownList过滤数据的一对多和多对多关系的ViewController
可能的原因 如果我的DropdownList代码没有错误,我用来显示数据的ViewModel没有对DropDownList项目的适当支持。
换句话说,RazorView和我的ViewModel与我想要达到的目标不兼容。如果我尝试更改我的ViewModel或RazorView,我会得到现有代码的无错循环错误。
或者Linq查询需要专家关注
这是FilterViewModel.cs
public IEnumerable <App> Apps { get; set; }
public IEnumerable <Language> Languages { get; set; }
public IEnumerable <Platform> Platforms { get; set; }
public IEnumerable <AgeGroup> AgeGroups { get; set; }
public IEnumerable <ProductCode> ProductCodes { get; set; }
这是AppsController.cs
public ActionResult FilterApps(App app)
{
var apps = _context.Apps.ToList();
var languages = _context.Languages.ToList();
var productCodes = _context.ProductCodes.ToList();
var platforms = _context.Platforms.ToList();
var ageGroups = _context.AgeGroups.ToList();
var viewModel = new FilterViewModel
{
AgeGroups = ageGroups,
Languages = languages,
Platforms = platforms,
ProductCodes = productCodes,
Apps = apps
.Where(a => a.LanguageId == app.LanguageId && a.PlatformId == app.PlatformId)
// I also tried all possible combinations :(a.Lanage.Id etc)
};
return View("FilterApps", viewModel);
}
以下是FilterApps.cshtml
@model Marketing.ViewModels.FilterViewModel
<h2>FilterApps</h2>
@using (Html.BeginForm("FilterApps", "Apps", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
@Html.DropDownListFor( m => m.Languages,
new SelectList(Model.Languages, "Id", "Name"),"Select Language",
new { @class = "form-control", @id = "dropDown" })
@Html.DropDownListFor(m => m.Platforms,
new SelectList(Model.Platforms, "Id", "Name"), "Select Platform",
new { @onchange = "this.form.submit();",
@class = "form-control", @id = "dropDown" })
</div>
}
//The existing code below is working fine so far.
@foreach (var group in Model.AgeGroups)
{
<h4>@group.Name</h4>
@foreach (var app in Model.Apps.OrderBy(a => a.AppOrder))
{
if (app.AgeGroupId == group.Id)
{
@app.ProductCode.Name
@app.Name
@app.Platform.Name
}
}
}
可能没用,但我希望其他信息会有所帮助。
其他信息
App.cs引用所有其他表,例如
public Language Language { get; set; }
public int LanguageId { get; set; }
public Platform Platform { get; set; }
public int PlatformId { get; set; }
and so on...
我已尝试过的内容 几个断点和日志来跟踪数据,我也尝试使用以下内容,但它破坏了我现有的排序和分组。
public App App { get; set; } //Instead of the IEnumerable<App>
答案 0 :(得分:2)
您的代码存在多个问题。
首先,您无法将<select>
元素绑定到复杂对象的集合。 <select>
会回复其所选选项的值(假设int
的{{1}}属性为Id
,则为Language
。)
接下来,模型中的视图为int
(并且您的生成表单控件具有基于这些属性的FilterViewModel
属性),但您发布回不同的模型(name
)不包含那些属性,所以无论如何都不会绑定。
您添加了App
标签选项(“选择语言”),如果选择了该选项,则会发布一个null
值,这会导致您的查询失败。
我也在下面提到了一些不良做法。
您的视图模型应为
null
我不清楚public class AppsFilterVM
{
public int? Language { get; set; }
public int? Platform { get; set; }
public IEnumerable<SelectListItem> LanguageOptions { get; set; }
public IEnumerable<SelectListItem> PlatformOptions { get; set; }
...
public IEnumerable <App> Apps { get; set; }
}
和AgeGroups
是什么,所以我在上面的代码中省略了它们,从您的评论中,我假设用户可以按ProductCodes
进行过滤或Language
或两者
控制器代码为
Platform
然后在视图中(注意它是进行GET,而不是POST)
public ActionResult FilterApps(AppsFilterVM model)
{
var apps = _context.Apps;
if (model.Language.HasValue)
{
apps = apps.Where(x => x.LanguageId == model.Language.Value);
}
if (model.Platform.HasValue)
{
apps = apps.Where(x => x.PlatformId == model.Platform.Value);
}
model.Apps = apps;
ConfigureViewModel(model);
return View(model);
}
private void ConfigureViewModel(AppsFilterVM model)
{
// populate the selectlists
var languages = _context.Languages;
var platforms = _context.Platforms
model.LanguageOptions = new SelectList(languages, "Id", "Name");
model.PlatformOptions = new SelectList(platforms , "Id", "Name");
}
还有一些你不应该做的事情。您为@model.AppsFilterVM
....
@using (Html.BeginForm("FilterApps", "Apps", FormMethod.Get))
{
@Html.LabelFor(m => m.Language)
@Html.DropdownListFor(m => m.Language, Model.LanguageOptions, "No filter")
@Html.ValidationMessageFor(m => m.Language)
@Html.LabelFor(m => m.Platform)
@Html.DropdownListFor(m => m.Platform, Model.PlatformOptions, "No filter")
@Html.ValidationMessageFor(m => m.Platform)
<input type="submit" value="Filter" />
}
@foreach (var group in Model.AgeGroups)
{
....
个元素提供了相同的<select>
属性,该属性是无效的html(id
方法已根据属性名称生成唯一的DropDownListFor()
。
您不应该根据id
change
事件提交表单。如果用户使用键盘浏览选项(例如使用箭头键,或者键入一个字符转到以该字母开头的第一个选项,然后表单将立即提交。此外,用户可能会先从第二个下拉列表中选择一个选项,该选项会在他们有机会选择该选项之前立即发布在第一个。允许用户进行选择,检查,然后在他们选择时提交表单。
您的视图不应包含linq查询,并且在将模型传递给视图之前,应在控制器中完成分组和排序。您的<select>
属性实际上应该是一个视图模型,其中包含组名称的属性和应用程序的集合属性(类似于previous question中的视图模型),因此视图很简单
Apps
您还应该考虑使用ajax来提交表单,该表单将调用单独的服务器方法,该方法返回仅@foreach(var group in Model.AgeGroups)
{
@group.Name
foreach (var app in group.Apps)
{
@app.ProductCode
@app.Name
@app.Platform
}
}
的部分视图,并在成功回调中更新DOM,这将提高性能。有关示例,请参阅Rendering partial view on button click in ASP.NET MVC。