views:

638

answers:

3

I am having a trouble while trying to create an entity with a custom view modeled create form. Below is my custom view model for Category Creation form.

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

and this is my user control where the UI is

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

When i click on save button, it doesnt bind the category for me because of i am using custom view model and strongly typed html helpers like that

<%=Html.TextBoxFor(model => Model.Category.OrderNo) %>

My html source looks like this

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

How can i fix this?

+2  A: 

You could use editor templates. Put your ascx control in ~/Views/Shared/EditorTemplates/SomeControl.ascx. Then inside your main View (aspx page) include the template like so (assuming your view is strongly typed to CategoryFormViewModel):

<%= Html.EditorForModel("SomeControl") %>

instead of

<% Html.RenderPartial("SomeControl", Model) %>
Darin Dimitrov
Thank you for the answer but it didnt work. My main view doesnt render the user control with EditorForModel
Barbaros Alp
Do you get some error message?
Darin Dimitrov
No, just getting the html page normally without the creation form
Barbaros Alp
This helped me, thanks!
John Buchanan
+4  A: 

Your View Model needs a default constructor without parameters and you need public set methods for each of the properties. The default model binder uses the public setters to populate the object.


The default model binder has some rules it follows. It chooses what data to bind to in the following order:

  1. Form parameters from a post
  2. Url route data defined by your route definitions in global.asax.cs
  3. Query string parameters

The default model binder then uses several strategies to bind to models/parameters in your action methods:

  1. Exact name matches
  2. Matches with prefix.name where prefix is the parent class and name is the subclass/property
  3. Name without prefix (as long as there are no collisions you don't have to worry about providing the prefix)

You can override the behavior with several options from the Bind attribute. These include:

  • [Bind(Prefix = "someprefix")] -- Forces a map to a specific parent class identified by the prefix.
  • [Bind(Include = "val1, val2")] -- Whitelist of names to bind to
  • [Bind(Exclude = "val1, val2")] -- Names to exclude from default behavior
Matt Spradley
In addition, you will need to make sure your action method's parameter is named category (or, if it's not, use the [Bind] attribute to set the prefix to "Category" so that it properly binds the values).
Brad Wilson
Hi Brad, thank you. Putting [Bind] infront of Category didnt work but changing the parameter name to category worked very well. So i need to name the parameters same as ViewModel.ParameterName if i want them to be bind when using custom view model, right ?
Barbaros Alp
Make sure you have a default constructor. It'd probably help if you posted the controller code so we can see what you mean by "It doesn't bind".
Haacked
A: 

make a default constructor for your viewmodel and initialize the Category there

public CategoryFormViewModel() { Category = new Category() }

and at your controller action receive the viewmodel

public ActionResult ActionName(CategoryFormViewModel model) { //here you can access model.Category.Title }