Установка выбранного свойства в SelectList для каждого объекта в коллекции на основе выбранного идентификатора в ASP.NET MVC 3

Ответьте на вопрос: Заполните свойство списка из строки с разделителями

Проблема, с которой я сталкиваюсь, состоит в том, что поля DropDown в моем представлении "Правка" не сохраняют / не выбирают нужный элемент на основе свойства AssignedUserID в модели BugAssignment.

Модели:

public class BugAssignment
{
    public int BugAssignmentID { get; set; }
    public int BugNumber { get; set; }
    public int? AssignedUserID { get; set; }
    public virtual User AssignedUser { get; set; }
    public virtual Status Status { get; set; }
    public IEnumerable<SelectListItem> Users { get; set; }
}

public class BugAssignmentList
{
    public BugAssignmentList()
    {
        BugAssignments = new List<BugAssignment>();
    }
    public int BugAssignmentListID { get; set; }
    public string Name { get; set; }
    public List<BugAssignment> BugAssignments { get; set; }
}

Редактировать / Подробности ViewModel

public class BugAssignmentListDetailsViewModel
{
    public int BugAssignmentListID { get; set; }
    public string Name { get; set;}
    public List<BugAssignment> BugAssignments { get; set; }
}

У меня есть следующие два метода в моем контроллере:

    public ActionResult Edit(int id)
    {
        var balData = db.BugAssignmentLists.Include(bn => bn.BugAssignments).ToList();
        //this is a reference to the bug assignment list object whose ID was passed in
        BugAssignmentList bugAssignmentList = balData.Where(b => b.BugAssignmentListID == id).FirstOrDefault();
        //loop through the bug assignment list and for each bug assignment
        foreach (BugAssignment b in bugAssignmentList.BugAssignments)
        {
            //create the select list for each BugAssignment object
            b.Users = users.Select(u => new SelectListItem
            {
                Value = u.UserID.ToString(),
                Text = u.FullName,
                Selected = u.UserID == b.AssignedUserID //<<THIS IS WHERE IT IS MESSING UP
            });

        }
        BugAssignmentListDetailsViewModel detailsVM = new BugAssignmentListDetailsViewModel
        {
            BugAssignmentListID = id
        };
        if (bugAssignmentList != null)
        {
            detailsVM.BugAssignments = bugAssignmentList.BugAssignments;
            detailsVM.Name = bugAssignmentList.Name;
        }
        return View(detailsVM);
    }

    // POST
    [HttpPost]
    public ActionResult Edit(BugAssignmentListDetailsViewModel viewModel)
    {
        var balData = db.BugAssignmentLists.Include(bn => bn.BugAssignments).ToList();
        var users = db.Users.ToList();
        BugAssignmentList bugAssignmentList = balData.Where(b => b.BugAssignmentListID == viewModel.BugAssignmentListID).FirstOrDefault();
        bugAssignmentList.Name = viewModel.Name;
        bugAssignmentList.BugAssignments = viewModel.BugAssignments;

        if (ModelState.IsValid)
        {
            UpdateModel(bugAssignmentList, "BugAssignmentList");
            db.Entry(bugAssignmentList).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(bugAssignmentList);
    }

Посмотреть:

<table>    
<thead>
    <th>
        Bug Number
    </th>
    <th>
        Assigned User
    </th>
</thead>
    @for(int i=0; i<Model.BugAssignments.Count(); i++)
    {
        <tr>
            <td style="text-align: center;">
                @Html.EditorFor(modelItem => Model.BugAssignments[i].BugNumber)
            </td>
            <td>
                @Html.DropDownListFor(modelItem => Model.BugAssignments[i].AssignedUserID, Model.BugAssignments[i].Users, "-- Select User --")
                @Html.HiddenFor(modelItem => Model.BugAssignments[i].BugAssignmentID)
            </td>
        </tr>
    }
</table>

POST работает нормально. При просмотре базы данных каждое BugAssignment в коллекции BugAssignments в BugAssignmentList обновляется с соответствующим AssignedUserID из выпадающего списка в моем представлении "Правка", поэтому это не метод POST.

Проблема в редактировании (int id). То, что происходит, очень странно. Я установил точку останова прямо перед циклом foreach и заглянул внутрь bugList.BugAssignments. Все AssignedUserID верны, но после завершения цикла, и я снова проверяю список, все SelectListItems в BugAssignment.Users имеют одного и того же выбранного пользователя.

Что не так с приведенным ниже кодом, который может вызвать это?

    foreach (BugAssignment b in bugAssignmentList.BugAssignments)
    {
        //create the select list for each BugAssignment object
        b.Users = users.Select(u => new SelectListItem
        {
            Value = u.UserID.ToString(),
            Text = u.FullName,
            Selected = u.UserID == b.AssignedUserID //<<THIS IS WHERE IT IS MESSING UP
        });

    }

Также, как примечание: я хочу, чтобы интерфейс выглядел примерно так (вот почему мне нужно, чтобы SelectList был в модели BugAssignment, если нет более простого способа. Я не хочу писать контроллер / представление BugAssignment Я хочу, чтобы кто-то мог быстро назначать пользователей на номера ошибок, например:введите описание изображения здесь

Вот еще один скриншот, который лучше показывает, что происходит:

введите описание изображения здесь

2 ответа

Решение

Я считаю, что это проблема закрытия. Попробуйте создать локальную копию b.assignedUserID:

foreach (BugAssignment b in bugAssignmentList.BugAssignments)
{
    var assignedUserID = b.AssignedUserID;

    //create the select list for each BugAssignment object
    b.Users = users.Select(u => new SelectListItem
    {
        Value = u.UserID.ToString(),
        Text = u.FullName,
        Selected = (u.UserID == assignedUserID),
    });

}

Я предполагаю, что это проблема с замыканиями. Поскольку вы генерируете SelectListItem внутри лямбды, то он получает копию только первого b.AssignedUserID и использует его везде. Некоторые материалы для чтения на эту тему: Есть ли причина для повторного использования C# переменной в foreach?

Я думаю, что эта модификация может решить проблему:

foreach (BugAssignment b in bugAssignmentList.BugAssignments)
    {
        var bugAssignedUser = b.AssignedUserID;
        //create the select list for each BugAssignment object
        b.Users = users.Select(u => new SelectListItem
        {
            Value = u.UserID.ToString(),
            Text = u.FullName,
            Selected = u.UserID == bugAssignedUser  //<<THIS IS WHERE IT IS MESSING UP
        });

    }
Другие вопросы по тегам