ViewModel с привязкой SelectList в ASP.NET MVC2

Я пытаюсь реализовать Редактирование ViewModel для моего объекта Linq2SQL, названного продуктом. Этому связали внешний ключ со списком брендов.

В настоящее время я заполняю список бренда через ViewData и использую DropDownListFor, таким образом:

<%= Html.DropDownListFor(model => model.BrandId, (SelectList)ViewData["Brands"])%> <%= Html.ValidationMessageFor(model => model.BrandId) %>

Теперь я хочу осуществить рефакторинг представление для использования ViewModel со строгим контролем типов и HTML. EditorForModel ():

<% using (Html.BeginForm()) {%>
    <%= Html.ValidationSummary(true) %>

    
Fields <%=Html.EditorForModel() %>

<% } %>

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

public class EditProductViewModel
{
    [HiddenInput]
    public int ProductId { get; set; }

    [Required()]
    [StringLength(200)]
    public string Name { get; set; }

    [Required()]
    [DataType(DataType.Html)]
    public string Description { get; set; }

    public IEnumerable Brands { get; set; }

    public int BrandId { get; set; }

    public EditProductViewModel(Product product, IEnumerable brands)
    {
        this.ProductId = product.ProductId;
        this.Name = product.Name;
        this.Description = product.Description;
        this.Brands = brands;
        this.BrandId = product.BrandId;
    }
}

Контроллер является установкой как так:

public ActionResult Edit(int id)
{
    BrandRepository br = new BrandRepository();

    Product p = _ProductRepository.Get(id);
    IEnumerable brands = br.GetAll().ToList().ToSelectListItems(p.BrandId);

    EditProductViewModel model = new EditProductViewModel(p, brands);

    return View("Edit", model);
}

ProductId, Имя и Описание отображаются правильно в сгенерированном представлении, но список выборки не делает. Список бренда определенно содержит данные.

Если я делаю следующее, по моему мнению, SelectList видим:

<% using (Html.BeginForm()) {%>
    <%= Html.ValidationSummary(true) %>

    
Fields <%=Html.EditorForModel() %>
<%= Html.LabelFor(model => model.BrandId) %>
<%= Html.DropDownListFor(model => model.BrandId, Model.Brands)%> <%= Html.ValidationMessageFor(model => model.BrandId) %>

<% } %>

Что я делаю неправильно? EditorForModel () не в общем поддерживают SelectList? Я пропускаю некоторый DataAnnotation?

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

8
задан Community 23 May 2017 в 10:24
поделиться

3 ответа

Junto,

метод Html.EditorForModel() недостаточно умен, чтобы сопоставить BrandId со списком Brands.

Во-первых, вы не можете использовать метод EditorForModel().
Вы должны создать свой собственный HTML-шаблон, как здесь.

<% using (Html.BeginForm()) { %>

    <div style="display:none"><%= Html.AntiForgeryToken() %></div>

    <table>
        <tr>
            <td><%= Html.LabelFor(m => m.Name) %></td>
            <td><%= Html.EditorFor(m => m.Name) %></td>
        </tr>

        <tr>
            <td><%= Html.LabelFor(m => m.Description) %></td>
            <td><%= Html.EditorFor(m => m.Description) %></td>
        </tr>

        <tr>
            <td><%= Html.LabelFor(m => m.BrandId) %></td>
            <td><%= Html.EditorFor(m => m.BrandId) %></td>
        </tr>
    </table>
<% } %>



Во-вторых, вам нужно изменить метод Action.

[ImportModelStateFromTempData]
public ActionResult Edit(int id)
{
    BrandRepository br = new BrandRepository();

    Product p = _ProductRepository.Get(id);
    ViewData["BrandId"] = br.GetAll().ToList().ToSelectListItems(p.BrandId);

    EditProductViewModel model = new EditProductViewModel(p);

    return View("Edit", model);
}



В-третьих, вам нужно обновить класс EditProductViewModel.

public class EditProductViewModel
{
    [Required]
    [StringLength(200)]
    public string Name { get; set; }

    [Required()]
    [DataType(DataType.Html)]
    public string Description { get; set; }

    [Required] // this foreign key *should* be required
    public int BrandId { get; set; }

    public EditProductViewModel(Product product)
    {
        this.Name = product.Name;
        this.Description = product.Description;
        this.BrandId = product.BrandId;
    }
}

Сейчас вы, вероятно, говорите: Чувак, где мое свойство [ProductId]?".
Короткий ответ: Оно вам не нужно!

HTML, отображаемый вашим представлением, уже указывает на метод действия "Edit" с соответствующим "ProductId", как показано ниже.

<form action="/Product/Edit/123" method="post">
    ...
</form>

Это ваш метод действия HTTP POST и он принимает 2 параметра.
"id" берется из атрибута действия тега

.

[HttpPost, ValidateAntiForgeryToken, ExportModelStateToTempData]
public ActionResult Edit(int id, EditProductViewModel model)
{
    Product p = _ProductRepository.Get(id);

    // make sure the product exists
    // otherwise **redirect** to [NotFound] view because this is a HTTP POST method
    if (p == null)
        return RedirectToAction("NotFound", new { id = id });

    if (ModelState.IsValid)
    {
        TryUpdateModel<Product>(p);
        _ProductRepository.UpdateProduct( p );
    }

    return RedirectToAction("Edit", new { id = id });
}

Очень полезны функции ExportModelStateToTempData и ImportModelStateFromTempData.
Эти атрибуты используются для шаблона PRG (Post Redirect Get).

Прочитайте этот раздел Использование шаблона PRG для модификации данных в этой статье блога Kazi Manzur Rashid.
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx




Хорошо, этот код связывания данных не является моим любимым способом.

TryUpdateModel<Product>( p );

Мой любимый способ - иметь отдельный интерфейс для чистого связывания данных.

public interface IProductModel
{
    public string Name {get; set;}
    public string Description {get; set;}
    public int BrandId {get; set;}
}

public partial class Product : IProductModel
{
}

public partial class EditProductViewModel : IProductModel
{
}

И именно так я буду обновлять свой код привязки данных.

TryUpdateModel<IProductModel>( p );

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

Дайте мне знать, если у вас есть какие-либо вопросы.

4
ответ дан 5 December 2019 в 23:14
поделиться

Вы должны встроить этот поиск в свою модель просмотра. Затем создайте объект Builder, который строит ViewModel и заполняет этот поиск.

В конце концов, именно для этого и предназначена ваша ViewModel: чтобы предоставить модель специально для вашего представления.

0
ответ дан 5 December 2019 в 23:14
поделиться

Новый атрибут DropDownList для вашего свойства BrandId может быть полезен. Просмотрите статью Расширение шаблонов ASP.NET MVC 2. Но этот подход использует ViewData в качестве источника элементов списка selectlist.

1
ответ дан 5 December 2019 в 23:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: