MVC将分组数据传递给视图

时间:2011-12-14 16:04:49

标签: asp.net-mvc views grouping

我是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>
  }
}

2 个答案:

答案 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>
  }
}