MVC Передача сгруппированных данных для просмотра - PullRequest
1 голос
/ 14 декабря 2011

Я новичок MVC, но пытаюсь реализовать лучшие практики и держать как можно меньше кода в представлении.Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть список участников и связанных с ними статусов.Я могу передать эту информацию представлению и отобразить каждого члена и его статус в одну строку, но я хочу, чтобы представление сгруппировало данные и выглядело следующим образом:

Status: Active
 - John Doe
 - Mary Jane
 - etc...
Status: Inactive
 - Mark Smith
 - etc...

Не думаю, что это лучшепрактиковаться, чтобы иметь какой-то многоуровневый цикл для представления (поправьте меня, если я ошибаюсь), и что у меня должно быть какое-то частичное представление для информации об элементе (прямо сейчас, только FirstName и LastName, но в конечном итогебыть более сложным), а затем какой-то основной вид для группировки по статусу, который затем отображает частичное представление для каждого члена.Я также пытаюсь использовать подход ViewModel для поддержания чистоты представлений.Любые предложения о том, как сделать это в соответствии с лучшими практиками, приветствуются!Также приветствуются любые комментарии к моему текущему коду (организация, чистота и т. Д.).

--- Если вы хотите посмотреть мой текущий код, он выглядит следующим образом ---

Вот контроллер, который отправляет результаты запроса в представление:

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

Вот представление и то, как оно использует модель представления для отображения имени и статуса каждого участника, но не сгруппировано:

@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>
}

ОБНОВЛЕНИЕ:Вот что мне пришлось изменить, чтобы оно работало на основе помощи Ромиаса

Обновите 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 ]

1 голос
/ 14 декабря 2011

Если у вас есть «статус» в ваших моделях, вы можете сделать 2 foreach ... Один зацикливается на 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>
  }
}
1 голос
/ 14 декабря 2011

Если значения статуса являются фиксированными, один из вариантов - изменить вашу ViewModel так, чтобы она содержала два списка членов - один для активных и другой для неактивных.

Независимо от того, сохраняете ли вы комбинированный список или нет, вы можете использовать пользовательский шаблон отображения для рендеринга фактического члена.Это позволит сохранить вид чистым и позволит вам добавлять будущие обновления дисплея в одном месте.

ОБНОВЛЕНИЕ:

Вот ссылка, которая показывает, как создавать шаблоны отображения, Для чего нужен синтаксис @ Html.DisplayFor?

В основном вы добавляете подпапку в соответствующую папку View (Home, Shared и т. Д.) С именем «DisplayTemplates».Создайте в этой папке ModelName.cshtml файлы с @model в качестве первой строки.С этого момента это стандартный Razor / Html, который вы бы поместили в свой цикл for.

Вы можете усложнить, если ваша ViewModel содержит Dictionary<string, List<MembersIndexViewModel>>.Строковым ключом будет ваш статус, а значением будет список членов с таким статусом.

Я бы начал с DisplayTemplate, прежде чем заняться вложенным списком.

---- ОБНОВЛЕНИЕ 2: рабочий пример -----

Базовый объект для члена:

public class MemberViewModel
{
    public string Status { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    /* ... other properties ... */
}

Модель представления для самой страницы, которая может содержать другие свойства при необходимости.:

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

Шаблон отображения для объекта-члена, расположенный в Views -> Home -> DisplayTemplates -> 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>
}

Это может быть излишним для вашего сценария, но, по крайней мере, вы можете увидеть, как это может работать.

...