我是MVC菜鸟,但是尝试实现最佳实践并尽可能在视图中保留尽可能少的代码。我遇到的问题是我有一个成员列表及其相关状态。我可以将此信息传递给视图并将每个成员及其状态呈现在一行中,但我希望视图对数据进行分组,如下所示:
Status: Active
- John Doe
- Mary Jane
- etc...
Status: Inactive
- Mark Smith
- etc...
我不认为在视图中使用某种多级for循环是最佳做法(如果我错了,请纠正我),并且我应该对成员信息有某种局部视图(右现在,只是FirstName和LastName,但最终会更复杂)然后是按状态分组的某种主视图,然后呈现每个成员的局部视图。我也尝试使用ViewModel方法来保持干净的视图。任何有关如何根据最佳实践做到这一点的建议表示赞赏!此外,欢迎任何关于我当前代码(组织,清洁度等)的评论。
---如果您想查看我当前的代码,则如下---
这是将查询结果发送到视图的Controller:
namespace MyApp.Web.Controllers
{
public class MemberController : Controller
{
private IMemberQueries _memberQuery;
public MemberController(IMemberQueries memberMemberQuery)
{
_memberQuery = memberMemberQuery;
}
public ViewResult Index()
{
return View(_memberQuery.GetMembersWithStatus());
}
}
}
以下是查询代码:
namespace MyApp.Web.ViewModels
{
public class MemberQueries : IMemberQueries
{
private IMemberRepository _memberRepository;
public MemberQueries(IMemberRepository memberMemberRepository)
{
_memberRepository = memberMemberRepository;
}
public IEnumerable<MembersIndexViewModel> GetMembersWithStatus()
{
return
_memberRepository.Member.Include(m => m.Status).Select(
m => new MembersIndexViewModel { FirstName = m.FirstName, LastName = m.LastName, Status = m.Status.StatusName });
}
}
}
这是我的ViewModel,用于限制进入视图的数据:
namespace MyApp.Web.ViewModels
{
public class MembersIndexViewModel
{
public string LastName { get; set; }
public string FirstName { get; set; }
public string Status { get; set; }
}
}
以下是视图以及它如何使用viewmodel显示每个成员的名称和状态,但它没有分组:
@model IEnumerable<MyApp.Web.ViewModels.MembersIndexViewModel>
<h2>Member List</h2>
@foreach (var member in Model)
{
<div>
<h3>@member.LastName, @member.FirstName - @member.Status</h3>
</div>
}
更新:根据Romias的帮助,我必须根据Romias的帮助进行更改
更新MemberQueries以调用ToList()以立即调用查询:
public IEnumerable<MembersIndexViewModel> GetMembersWithStatus()
{
return
_memberRepository.Member.Include(m => m.Status).Select(
m => new MembersIndexViewModel { FirstName = m.FirstName, LastName = m.LastName, Status = m.Status.StatusName }).ToList();
}
以下是现在有效的更新视图:
<h2>Member List</h2>
@foreach (string status in Model.Select(x => x.Status).Distinct())
{
<h2>@status:</h2>
string memberStatus = status;
foreach (MembersViewModel member in Model.Where(m => m.Status == memberStatus))
{
<div>@member.LastName, @member.FirstName</div>
}
}
答案 0 :(得分:1)
如果 状态值已修复,则可以选择修改ViewModel以包含两个成员列表 - 一个用于活动,另一个用于非活动。
无论您是保留合并列表还是拆分合并列表,都可以使用custom display template呈现实际成员。这样可以保持视图干净,并允许您在一个位置添加未来的显示更新。
<强>更新强>
这是一个显示如何创建显示模板的链接。 What is the @Html.DisplayFor syntax for?
您基本上将子文件夹添加到名为“DisplayTemplates”的相应View文件夹(Home,Shared等)中。在该文件夹中创建具有@model作为第一行的ModelName.cshtml文件。从那时起,它将放入你的for循环中的标准Razor / Html。
让ViewModel包含Dictionary<string, List<MembersIndexViewModel>>
会让您变得更加复杂。字符串键将是您的状态,值将是具有该状态的成员列表。
在处理嵌套List之前,我将从DisplayTemplate开始。
----更新2:一个工作示例-----
成员的基础对象:
public class MemberViewModel
{
public string Status { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
/* ... other properties ... */
}
页面本身的ViewModel,可以根据需要包含其他属性:
public class MemberIndexViewModel
{
// view may need additional info outside of the status list
public string SomeOtherData { get; set; }
public Dictionary<string, List<MemberViewModel>> MembersByStatus { get; set; }
public MemberIndexViewModel()
{
MembersByStatus = new Dictionary<string, List<MemberViewModel>>();
}
}
用于返回成员列表的模拟函数:
private List<MemberViewModel> MockDataFromDB()
{
List<MemberViewModel> members = new List<MemberViewModel>();
for (var i = 0; i < 20; i++)
{
var m = new MemberViewModel();
if (i < 10)
m.Status = "Active";
else if (i < 15)
m.Status = "Inactive";
else
m.Status = "Unknown";
m.FirstName = "First" + i.ToString();
m.LastName = "Last" + i.ToString();
members.Add(m);
}
return members;
}
控制器操作从数据库获取数据,然后通过将成员排序到适当的列表中来构建相应的视图模型:
[HttpGet]
public ActionResult Test3()
{
var members = MockDataFromDB(); // get the data from the DB
var vm = new MemberIndexViewModel();
vm.SomeOtherData = "Something else the view may need.";
foreach (var m in members)
{
if (!vm.MembersByStatus.ContainsKey(m.Status))
vm.MembersByStatus.Add(m.Status, new List<MemberViewModel>());
vm.MembersByStatus[m.Status].Add(m);
}
return View(vm);
}
位于视图中的成员对象的显示模板 - &gt;主页 - &gt; DisplayTemplates - &gt; MemberViewModel.cshtml:
@model ViewModel.MemberViewModel
<div>@Model.FirstName @Model.LastName</div>
最后,将这一切联系在一起的观点:
@model ViewModel.MemberIndexViewModel
<span>SomeOtherData: </span><span class="display-field">@Html.DisplayFor(model => model.SomeOtherData)</span>
<hr />
@foreach (var group in Model.MembersByStatus)
{
<fieldset>
<legend>@group.Key</legend>
@Html.DisplayFor(m => group.Value)
</fieldset>
}
对于您的方案,这可能有点过头了,但至少您可以看到它是如何工作的。
答案 1 :(得分:1)
一旦你的模特中有“状态”,你就可以做2个... 一个循环遍历ACTIVE,另一个循环为非活动。
或
你可以循环一次,将字符串变量中的活动用户的html与另一个变量中的其他用户连接起来。然后只显示每个变量的串联。
修改强> 如果状态未修复,则可以创建嵌套的foreach。第一个按状态选项循环,在内循环中按状态过滤用户集合。
这样您可以添加具有状态的标签,然后添加所有用户。然后是另一个具有下一个状态的标签及其用户。
可以使用显示模板显示用户。
第二次编辑:伪代码
@model IEnumerable<MyApp.Web.ViewModels.MembersIndexViewModel>
<h2>Member List</h2>
@foreach (var myStatus in ()ViewBag.StatusList){
<h3>@myStatus</h3>
@foreach (var member in Model.Where(status == myStatus ))
{
<div>
<h3>@member.LastName, @member.FirstName - @member.Status</h3>
</div>
}
}