This content is archived. See latest version here.

Last updated: Mar 31 2014

Table of contents

Introduction

When working with EPiServer content data in MVC, the view does not 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 view cannot know any connections between the properties on the view model and the properties on the content data object. This makes it impossible to update parts of the page when changing content in the form edit view. 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 is 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 content is displayed in edit view. The wrapping element will have attributes with the connection to the content data property. As default, the wrapping element will be a div, but it is possible to change the element by adding CustomTag to the list in additionalViewData (new { CustomTag = "span" }) in the overloads of PropertyFor which contains additionalViewData. If a wrapping element in edit view cannot 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 cannot have a one to one relation with a property on the view model. For example, the property ShowBanner will display a banner on the page if the property is set to true. This property probably 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 is 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 view 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 is possible to change the element by adding editepielementname to the list in additionalViewData (new { editepielementname = "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 view.

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