MVC - Using view models

Vote:
 

How do I work with view models?

This doesn't work,

public ActionResult Index(SomePage currentPage)
{
var model = new SomePageModel
{
PageData = currentPage
};

return View(model);
}

Since the action expects a SomePage object, I can't return a SomePageModel object, which is reasonable. But as I understand it, to get the currentPage data object I need to have (SomePage currentPage).

So how do I do this right?

#77732
Nov 25, 2013 14:33
Vote:
 

What is your controller inheriting from? Are you inheriting from EPiServer.Web.Mvc.PageController<SomePage>?

#77741
Edited, Nov 25, 2013 15:33
Vote:
 

Basically, your controller should look something like this:

    public class TextPageController : PageController<TextPage>
    {
        public ActionResult Index(TextPage currentPage)
        {
            var viewModel = new TextPageViewModel(currentPage);
            AutoMapper.Mapper.Map(currentPage, viewModel);
            return View(viewModel);
        }
    }

   

Your view should be in Views\TextPage\Index.cshtml and should declare the correct Model:

@using EPiServer.Web.Mvc.Html
@model Xx.Web.Views.TextPage.TextPageViewModel

 

#77742
Nov 25, 2013 15:38
Vote:
 

Hi Johan,

First of all, your page controller must inherit from PageController<T>, like this:

public class SomePageController : PageController<SomePage>

    

Since the action expects a SomePage object, I can't return a SomePageModel object

Actually, you can return any action result you want.

public class SomePageController : PageController<SomePage>
{
    public MvcHtmlString Index(SomePage currentPage)
    {
        return new MvcHtmlString("This works, too!");
    }
}

    

Index(SomePage currentPage) part is called model binding. You can find more info about model binding on the following link http://msdn.microsoft.com/en-us/magazine/hh781022.aspx

EPiServer has created their own model binder, and you need to follow their name convention in order to make it work. So you can't have SomePage myPage, you must use SomePage currentPage for pages, and SomePage currentBlock for blocks.

 

Let's say that you have defined your page type like this

[ContentType(GUID = "2F5BE1AA-2E32-43C7-8520-39A9C91DB069")]
public class SomePage : PageData
{
    public virtual string SomeProperty { get; set; }
}

    

In case you wan't to work with SomePage directly, you would have something like this:

Controller

public class SomePageController : PageController<SomePage>
{
    public ActionResult Index(SomePage currentPage)
    {
        return View(currentPage);
    }
}

    

View

@model SomePage
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
    </head>
    <body>
        @Html.RenderEPiServerQuickNavigator()
        @Html.FullRefreshPropertiesMetaData()
        <div>
            <p @Html.EditAttributes(x => x.SomeProperty)>@Html.DisplayFor(x => x.SomeProperty)</p>
        </div>
    </body>
</html>

    


In case you want to have a ViewModel that has a reference to CurrentPage, you would have something like this:

ViewModel

public class SomePageViewModel
{
    public SomePage CurrentPage { get; set; }
    // other properties
}

    

Controller

public class SomePageController : PageController<SomePage>
{
    public ActionResult Index(SomePage currentPage)
    {
        var viewModel = new SomePageViewModel { CurrentPage = currentPage };
        return View(viewModel);
    }
}

    

View

@model SomePageViewModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
    </head>
    <body>
        @Html.RenderEPiServerQuickNavigator()
        @Html.FullRefreshPropertiesMetaData()
        <div>
            <p @Html.EditAttributes(x => x.CurrentPage.SomeProperty)>@Html.DisplayFor(x => x.CurrentPage.SomeProperty)</p>
        </div>
    </body>
</html>

    


Or in case you don't want your view model to have a reference to CurrentPage, you could have something like this as well:

ViewModel

public class SomePageViewModel
{
    public string SomeProperty { get; set; }
    // other properties
}

    

Controller

public class SomePageController : PageController<SomePage>
{
    public ActionResult Index(SomePage currentPage)
    {
        var viewModel = new SomePageViewModel { SomeProperty = currentPage.SomeProperty };
        return View(viewModel);
    }
}

    

View

@model SomePageViewModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Index</title>
    </head>
    <body>
        @Html.RenderEPiServerQuickNavigator()
        @Html.FullRefreshPropertiesMetaData()
        <div>
            <p @Html.EditAttributes(x => x.SomeProperty)>@Html.DisplayFor(x => x.SomeProperty)</p>
        </div>
    </body>
</html>

    


Make sense?

#77752
Edited, Nov 26, 2013 0:55
Vote:
 

Hey Dejan, all that makes perfect sense and was the way I thought it would work.

I found my problem. My view was still using the SomePage object as a model and not the new SomePageModel object.

Thanks for a good and thorough response.

#77766
Edited, Nov 26, 2013 9:06
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.