O ViewModel personalizado com MVC 2 HTML HELHEDERS DETILHO DE RETILHAR OBJETO NULL ON CREATE?
-
21-09-2019 - |
Pergunta
Estou tendo um problema ao tentar criar uma entidade com uma visualização personalizada Criar formulário. Abaixo está o meu modelo de visualização personalizado para o formulário de criação de categoria.
public class CategoryFormViewModel
{
public CategoryFormViewModel(Category category, string actionTitle)
{
Category = category;
ActionTitle = actionTitle;
}
public Category Category { get; private set; }
public string ActionTitle { get; private set; }
}
E este é o meu controle de usuário onde a interface do usuário está
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CategoryFormViewModel>" %>
<h2>
<span><%= Html.Encode(Model.ActionTitle) %></span>
</h2>
<%=Html.ValidationSummary() %>
<% using (Html.BeginForm()) {%>
<p>
<span class="bold block">Başlık:</span>
<%=Html.TextBoxFor(model => Model.Category.Title, new { @class = "width80 txt-base" })%>
</p>
<p>
<span class="bold block">Sıra Numarası:</span>
<%=Html.TextBoxFor(model => Model.Category.OrderNo, new { @class = "width10 txt-base" })%>
</p>
<p>
<input type="submit" class="btn-admin cursorPointer" value="Save" />
</p>
<% } %>
Quando clico no botão Salvar, ele não vincula a categoria para mim por causa de eu estou usando o modelo de exibição personalizado e digitou fortemente os ajudantes HTML como esse
<%=Html.TextBoxFor(model => Model.Category.OrderNo) %>
Minha fonte HTML se parece com isso
<form action="/Admin/Categories/Create" method="post">
<p>
<span class="bold block">Başlık:</span>
<input class="width80 txt-base" id="Category_Title" name="Category.Title" type="text" value="" />
</p>
<p>
<span class="bold block">Sıra Numarası:</span>
<input class="width10 txt-base" id="Category_OrderNo" name="Category.OrderNo" type="text" value="" />
</p>
<p>
<input type="submit" class="btn-admin cursorPointer" value="Kaydet" />
</p>
</form>
Como posso consertar isso?
Solução
Seu modelo de visualização precisa de um construtor padrão sem parâmetros e você precisa de métodos de conjunto público para cada uma das propriedades. O Binder do modelo padrão usa os setters públicos para preencher o objeto.
O fichário padrão do modelo tem algumas regras que segue. Ele escolhe quais dados vinculados na seguinte ordem:
- Parâmetros de formulário de uma postagem
- Dados de rota de URL definidos por suas definições de rota no global.asax.cs
- Parâmetros de sequência de consulta
O Binder do modelo padrão usa várias estratégias para se ligar aos modelos/parâmetros em seus métodos de ação:
- Nome exato corresponde
- Combina com prefix.name onde o prefixo é a classe pai e o nome é a subclasse/propriedade
- Nome sem prefixo (desde que não haja colisões, você não precisa se preocupar em fornecer o prefixo)
Você pode substituir o comportamento por várias opções do atributo de ligação. Esses incluem:
- Bind (prefix = "someprefix") - força um mapa para uma classe pai específica identificada pelo prefixo.
- Bind (incluir = "val1, val2") - Lista de nomes para se ligar a
- Bind (exclude = "val1, val2") - Nomes a serem excluídos do comportamento padrão
Outras dicas
Você pode usar modelos de editor. Coloque seu controle ASCX em ~/Views/Shared/EditorTemplates/SomeControl.ascx
. Em seguida, dentro da sua visualização principal (página aspx) inclui o modelo como assim (supondo que sua visão seja fortemente digitada para CategoryFormViewModel
):
<%= Html.EditorForModel("SomeControl") %>
ao invés de
<% Html.RenderPartial("SomeControl", Model) %>
Faça um construtor padrão para o seu ViewModel e inicialize a categoria lá
public CategoryFormViewModel()
{
Category = new Category()
}
E na ação do seu controlador receber o viewmodel
public ActionResult ActionName(CategoryFormViewModel model)
{
//here you can access model.Category.Title
}