This content is retired. See latest version here.

Last updated: Mar 25 2013

Introduction

When working with EPiServer content data in MVC, the view doesn't have to take the content data object as view model. The content data that is received in the controller when the page is loaded can be be used to populate a view model to be used in the view. When using a view model instead of the content data object in the view, the edit mode can't know any connections between the properties on the view model and the properties on the content data object. This makes it imposible to update parts of the page when changing content in the form edit mode. To make it possible to show the correct data directly on the preview window then editing the page, some helper methods can be used.

Property connections

To make a connection between a property on the view model and a property on the content data, the extension method 'GetEditHints' can be used on the ViewData property in the controller. The extension method is located in EPiServer.Web.Mvc. This method will return a class which handles two collections on the ViewData object. Those are connections between properties on the view model and properties on the content data, as well as properties which needs full refresh. "AddConnection" on the class uses Expressions to get the property from the view model and and the property from the content data object, which should be connected. It's also possible to work directly with the ViewData object to set connections between properties. This can be done by casting ViewData[EPiServer.Web.Mvc.ViewDataKeys.PropertyConnections] to IList<EditHint>, and adding edit hints to the collection.

When the property, with a connection to a content data property, should be displayed in the view, the "Html.PropertyFor" extension method in the EPiServer.Web.Mvc.Html namespace is the easiest way to use the connection. This method will create a wrapper element around the property when the contnet is displayed in edit mode. The wrapping element will have attributes with the connection to the content data propety. As default, the wrapping element will be a div, but it's possible to change the element by adding "editepielementname" to the list in "additionalViewData" (new { editepielementname = "span" }) in the overloads of PropertyFor which contains "additionalViewData". If a wrapping element in edit mode can't be used, the extension method "EditAttributes" can be used instead. This method will only write the attributes for connecting the element to a property on the content data object.

It is also possible to make connections between properties directly in the view. By using the "Html.PropertyFor" extensions with the "EditHint" overload, a connection will be made to the view data property by setting the "ContentDataPropertyName" on the "EditHint" object.

When a property on the view model has the same name as the property on the content data object, a connection will be made automatically in edit mode when using "Html.PropertyFor".

Full refresh properties

Some content data properties can't have a one to one relation with a property on the view model. For example, the property "ShowBanner" will diplay a banner on the page if the property is set to true. This property probobly needs a full refresh of the page to render a correct preview, since it can affect a lot of things on the page. To add a property to the full refresh list, the extension method 'GetEditHints' can be used on the ViewData property in the controller. The extension method is located in EPiServer.Web.Mvc. This method will return a class which handles two collections on the ViewData object. Those are connections between properties on the view model and properties on the content data, as well as properties which needs full refresh. "AddFullRefreshFor" on the class uses Expressions to get the property from the content data object, which will be added to the list. It's also possible to work directly with the ViewData object to set a property to the full refresh list. This can be done by casting ViewData[EPiServer.Web.Mvc.ViewDataKeys.FullRefreshProperties] to IList<EditHint>, and adding a edit hints to the collection with the "ContentDataPropertyName" set to the property name.

The collection needs to be rendered somewhere on the page, and the easiest way is to use the extension method "Html.FullRefreshPropertiesMetaData()". The extension method also contains an overload which takes an array of property names. Then the overload with the string array is used, only the property names in the array will be added for full refresh. The default method will add the properties in the ViewData collection.

Html.PropertyFor

The "Html.PropertyFor" methods are wrappers around "Html.DisplayFor", which will create connections between view model properties and content data properties in edit mode. In view mode, the "PropertyFor" will directly call "DisplayFor", but in edit mode a wrapping element will be created around the property which will contain a connection to a content data property (if a connection exist). As default, the wrapping element will be a div, but it's possible to change the element by adding "customtag" to the list in "additionalViewData" (new { customtag = "span" }) in the overloads of PropertyFor which contains "additionalViewData".

Html.FullRefreshPropertiesMetaData

The "Html.FullRefreshPropertiesMetaData()" extensions contains one method without any parameters and one which takes an array of property names. The default method, without parameters, will add the properties in the ViewData collection for full refresh. When the overload with the string array is used, only the property names in the array will be added for full refresh.

Html.EditAttributes

The extension methods "EditAttributes" can be used to add attributes to an existing element, which will make the content in the element connected to a property on the content data object. By specifying which property on the content data object the element will connect to, the connection will be made in edit mode.

Html.BeginEditSection

The extension methods "BeginEditSection" and "EndEditSection" works as "EditAttributes" in meaning it adds attributes needed for editing. It should be used when adding attributes to a property that can contain nested properties (for example a block) or when rendering a property that can be nested (for example a partial view for a block). "BeginEditSection" will make sure that only the outer property will get edit hints when there are nested properties. When rendering a block that means that the block property will get edit hints while the individual properties within the block will not get edit hints.

Example

The following example contains a page type, a controller, a model view, and a view.

C#
public class EditHintSample : PageController<EditSamplePage>
{
    public ActionResult Index(EditSamplePage currentPage)
    {
        var model = new EditSampleViewModel
        {
            Heading = currentPage.MyText,
            Body = currentPage.MainBody,
            SecondaryBody = currentPage.SecondaryBody,
            BannerUrl = currentPage.BannerUrl.ToString(),
            ShowBanner = currentPage.ShowBanner
        };

        // Get the edit hint collections
        var editingHints = ViewData.GetEditHints<EditSampleViewModel, EditSamplePage>();

        // Adds a connection between 'Heading' in view model and 'MyText' in content data.
        editingHints.AddConnection(m => m.Heading, p => p.MyText);

        // Add the property 'ShowBanner' to the collection of properties which requires full refresh of the page.
        editingHints.AddFullRefreshFor(p => p.ShowBanner);

        return View(model);
    }
}

public class EditSampleViewModel
{
    public string Heading { get; set; }
    public string BannerUrl { get; set; }
    public XhtmlString Body { get; set; }
    public XhtmlString SecondaryBody { get; set; }
    public virtual bool ShowBanner { get; set; }
}

[ContentType]
public class EditSampleBlock : BlockData
{
    public virtual string Heading { get; set; }
    public virtual XhtmlString Body { get; set; }
}

[ContentType]
public class EditSamplePage : PageData
{
    public virtual string MyText { get; set; }
    public virtual XhtmlString MainBody { get; set; }
    public virtual XhtmlString SecondaryBody { get; set; }
    public virtual Url BannerUrl { get; set; }
    public virtual bool ShowBanner { get; set; }
    public virtual EditSampleBlock TextBlock { get; set; }
}
C#
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<CodeSamples.EPiServerNET.Web.Mvc.EditSampleViewModel>" %>
<%@ Import Namespace="EPiServer.Web.Mvc.Html" %>

<%: Html.FullRefreshPropertiesMetaData() %>

<h1 <%: Html.EditAttributes(m => m.Heading) %>>
    <%: Model.Heading %>
</h1>

<% if (Model.ShowBanner) { %>
    <div <%: Html.EditAttributes(m => m.BannerUrl) %>>
        <img src="<%: Model.BannerUrl %>" />
    </div>
<% } %>

<%: Html.PropertyFor(m => m.Body, new EPiServer.Web.Mvc.EditHint() { ContentDataPropertyName = "MainBody" } ) %>
<%: Html.PropertyFor(m => m.SecondaryBody) %>

<%: Html.BeginEditSection("div", p => p.TextBlock) %>>
    <%: Html.Partial("TextBlock", Model.TextBlock )%>
<%: Html.EndEditSection("div")%>>

Comments