views:

395

answers:

4

Controller

public ActionResult Create()
{
   return View(new PageViewModel());
} 

[HttpPost]
public ActionResult Create(Page page)
{
   try
   {
      repPage.Add(page);
      repPage.Save();

      return RedirectToAction("Edit");
   }
   catch
   {
      return View(new PageViewModel());
   }
}

PageViewModel

public class PageViewModel
{
    public Page Page { get; set; }
    public List<Template> Templates { get; set; }

    private TemplateRepository repTemplates = new TemplateRepository();

    public PageViewModel()
    {
        Page = new Page();
        Templates = repTemplates.GetAllTemplates().ToList(); 
    }
}

Parts of my View

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Website.Models.PageViewModel>" %>

<%= Html.TextBoxFor(model => model.Page.Name, new { @style = "width:300px;" })%>

<%= Html.DropDownListFor(model => model.Page.Template, new SelectList(Model.Templates, "ID", "Name"), new { @style = "width:306px;" })%>

Template: ID Name
Page: ID Name TemplateID

My dropdownlist is populated correctly in the view, no problems there. My problem is that I dont get the selected value from the dropdownlist.

In my controller I i put a breakpoint in Edit and see that the Name textbox is populated with the value I type into it. But the selected from the dropdownlist is set to null.

alt text

Am I missing something, I thought it should set the correct Template value into the Page object. What am I doing wrong?

+1  A: 

Try something like this maybe? The key in the collection is the name of the dropdownlist control...

[AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(FormCollection collection)
        {
           try
           {
              string selectedvalue = collection["Template"];

              return RedirectToAction("Edit");
           }
           catch
           {
              return View(new PageViewModel());
           }
        }
gmcalab
`int templateID = int.Parse(collection["Page.Template"]);` this code returns the template id correctly as you wrote. But is it possible to get the value from a strongly typed object, rather than the `FormCollection` and writing "Page.Template"?
Martin
+1  A: 

The only thing that you get back from the web page is the id of the selected template. The default model binder doesn't know how to take this id and retrieve the correct template object from your repository. To do this you would need to implement a custom model binder that is able to retrieve the values from the database, construct a Template object, and assign it to the Page. Or... you could do this manually in the action given that, according to your comments elsewhere, you know how to get the template's id from the posted values.

tvanfosson
A: 

Ok, I did like this:

        [HttpPost]
        public ActionResult Create(FormCollection collection)
        {
            try
            {
                Page page = new Page();
                page.Name = collection["Page.Name"];
                page.TemplateID = int.Parse(collection["Page.Template"]);
                page.Created = DateTime.Now;

                repPage.Add(page);
                repPage.Save();

                return RedirectToAction("Edit");
            }
            catch
            {
                return View(new PageViewModel());
            }
        }

And it works good, I just wanted to know if there is a better way to to this without manually getting the values from the collection.

But I guess it is not possible without making your own model binder as tvanfosson said.

Thank you everyone.

Martin
Certainly would be nice for this to happen with the default MVC model binder. If someone finds a cleaner solution, chime in!
Roger Rogers
A: 

for model binding, use in the ActionResult:

partial ActionResult(FormCollection form)
{
    Page page = new Page();
    UpdateModel(page);
    return view(page);
}

your class:

public class Page
{
  public string Name {get; set;}
  public int Template {get; set;}
  public DateTime Created {get; set;}

  public Page()
  {
    this.Created = DateTime.Now;
  }

}

attribute names in your class should be equal to the name of the fields of view

SeWa