ASP.Net Filter下拉列表项目来自多个表



摘要:

我正在尝试使用两个DropDownList控件来过滤当前正在视图中排序和显示的数据。

我们将要学习的内容为一对多和多对多关系创建ViewController,该关系可以使用DropDownList 过滤数据

可能的原因如果我的DropdownList代码没有严重错误,那么我用来显示数据的ViewModel对DropdownList项没有适当的支持。

换句话说,RazorView和我的ViewModels与我想要实现的目标不兼容。如果我试图更改ViewModel或RazorView,我会得到现有代码的错误循环。

或者Linq Query需要一个专家关注

这里是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> 

您的代码存在多个问题。

首先,不能将<select>元素绑定到复杂对象的集合。<select>返回其所选选项的值(假设LanguageId属性为int,则该值将是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; }
}

不清楚AgeGroupsProductCodes是什么用的,所以我在上面的代码中省略了它们,从你的评论中,我假设用户可以通过LanguagePlatform或两种进行过滤

控制器代码为

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");
}

然后在视图中(注意它正在进行GET,而不是POST)

@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>元素提供了相同的id属性,该属性是无效的html(DropDownListFor()方法已经根据属性名称生成了一个唯一的id)。

您不应该基于<select>change事件提交表单,这不仅是意外行为,如果用户使用键盘浏览选项(例如,使用箭头键,或键入一个字符转到以该字母开头的第一个选项,然后表单将立即提交。此外,用户可以先从第二个下拉列表中选择一个选项,该选项将在他们有机会选择第一个选项之前立即发布。允许用户进行选择,检查,然后提交表单。)如果他们选择的话。

视图不应包含linq查询,在将模型传递给视图之前,应在控制器中进行分组和排序。事实上,Apps属性应该是一个视图模型,其中包含组名称的属性和应用程序的集合属性(类似于您上一个问题中的视图模型),因此视图只是

@foreach(var group in Model.AgeGroups)
{
@group.Name
foreach (var app in group.Apps)
{
@app.ProductCode
@app.Name
@app.Platform
}
}

您还应该考虑使用ajax提交表单,它将调用单独的服务器方法,该方法只返回Apps的部分视图,并在成功回调中更新DOM,这将提高性能。有关示例,请参阅ASP中单击按钮时渲染局部视图。NET MVC。

最新更新