+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Introducing PageTitleMode for ModuleBuilder DynamicContentView

by Boyan Barnev

Some of you have shown particular interest in controlling the Page title behavior when viewing ModuleBuilder items. While we have this task on our to-do list, we decided that it'd be good to provide you with a solution before the actual feature implementation.

With this blog post we're going to show you how you can:

1. Create a customized DynamicContentView widget, which inherits from the default one and implement your own behavior

2. Automatically configure the custom DynamicContentView to work with a particular Module Builder type

3. Implement the PageTitleMode logic as in the current ContentView widgets

 

Please find the detailed steps below:

 

1. Creating the customized DynamicContentView widget

 To extend the default DynamicContentView with our own logic we can simply create a new class in our project and inherit from Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView. For this particular example we do not need to change any of the default designer or definition so just by doing:

namespace SitefinityWebApp
{
    public class DCVCustom : DynamicContentView
    {
    }
}

we already have a working DynamicContentView.

 

2. Configuring the new widget to work with a particular Module Builder module

One thing worth noting, is that unlike ContentView widgets, where you have a separate widget for each content type (e.g. NewsView, EventsView etc.) with Module Builder all modules automatically register an instance of the same control type - DynamicContentView.

How do we get a readily configured widget that works with our specific type then? It's actually very easy - we have exposed three properties that need to be set in the widget registration in the toolbox, that allow you to differentiate between the different Module Builder created modules.

If we take for example one of my modules created with Module Builder - "Sections", here's the widget registration in the ToolboxesConfig.config:

<add enabled="True" type="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend.DynamicContentView, Telerik.Sitefinity, Version=5.0.2500.0, Culture=neutral, PublicKeyToken=b28c218413bdf563" title="Sections" cssClass="sfNewsViewIcn" moduleName="DynamicModule" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.Sections.Section" DefaultMasterTemplateKey="d7632471-8a02-4d3f-89ad-c0268eed5735" DefaultDetailTemplateKey="22affc46-7b7e-480e-9245-d085cdea2e8a" visibilityMode="None" name="Telerik.Sitefinity.DynamicTypes.Model.Sections.Section" />
 You can notice that his widget registration differs slightly with the DynamicContentTypeName, DefaultMasterTemplateKey, and DefaultDetailTemplateKey properties. The DynamicContentTypeName represents your Module Builder module type, while the latter DefaultMasterTemplateKey and DefaultDetailTemplateKey  are just the IDs of your List and Single Item templates. So for the purposes of registering my custom DynamicContentView in the toolbox, and make it work with a particular Module Builder type, all I need to do is copy these three properties in my widget registration. Finally here's what my custom widget which will work again with the "Secitons" Module Builder module looks like:
<add enabled="True" type="SitefinityWebApp.DCVCustom" title="DCVCustom" description="DCVCustom" DynamicContentTypeName="Telerik.Sitefinity.DynamicTypes.Model.Sections.Section" DefaultMasterTemplateKey="d7632471-8a02-4d3f-89ad-c0268eed5735" DefaultDetailTemplateKey="22affc46-7b7e-480e-9245-d085cdea2e8a"  visibilityMode="None" name="DCVCustom" />

 

3. Implementing  PageTitleMode for our widget

As you probably know we already can control the Page title behavior in our Content modules - this is controlled by the PageTitleMode property of each ContentView widget.

The PageTitleMode property can be set to: Replace, DoNotSet, and Append; which pretty much explains what ti does - it can replace the current page title with the title of the currently displayed Module Builder item, or alternatively Append it to the title. Of course you have the choice of not changing the title at all, by selecting DoNotSet.

 

First we need to expose a public property to hold our selection for PageTitleMode :

# region Properties
      
       public PageTitleModes PageTitleModeInternal { get; set; }
 
       public DynamicContent DetailItem { get; set; }
 
       /// <summary>
       /// Defines identifiers that indicate if and how the page title should be set.
       /// </summary>
       public enum PageTitleModes
       {
           /// <summary>
           /// Indicates that the page title should be replaced by the item title.
           /// </summary>
           Replace,
           /// <summary>
           /// Indicates that the page title should not be altered.
           /// </summary>
           DoNotSet,
           /// <summary>
           /// Indicates that the item title should be appended to the page title.
           /// </summary>
           Append
       };
 
       # endregion

We can then use this selection to determine what shall we do with the Page title:

protected virtual void ResolvePageTitle()
       {
           if (this.DetailItem == null || this.Page == null)
               return;
           if (this.PageTitleModeInternal == PageTitleModes.DoNotSet)
               return;
 
           DynamicContent cnt = this.DetailItem as DynamicContent;
 
           if (cnt == null)
               return;
 
           if (this.IsSingleItem())
           {
               var title = cnt.GetValue<String>("Title");
               switch (this.PageTitleModeInternal)
               {
                   case PageTitleModes.Append:
                       if (title != null)
                           this.Page.Title = String.Format("{0} {1}", this.Page.Title, title);
                       break;
                   case PageTitleModes.Replace:
                       if (title != null)
                           this.Page.Title = title;
                       else
                           this.Page.Title = "";
                       break;
               }
           }
       }

As you have noticed from the above method, we would need to determine two things in order for this functionality to work correctly:

 

1. Check if the control is displaying a single item - this can be achieved very easily, as we already have an out of the box logic for doing this - the IsSingleItem() method of the base class DynamicContentView will return true or false, upon which we can do our conditional logic when the widget is displaying a single item.

 

2. Once we've determined a single item being displayed, we need to actually get it and retrieve its Title propety, so we can operate with it:

protected void SetSingleItem()
        {
            if (this.DetailViewDefinition.DataItemId != Guid.Empty)
            {
                this.DetailItem = this.DynamicManager.GetDataItem(this.DynamicContentType, this.DetailViewDefinition.DataItemId);
            }
 
            var urlParameters = this.GetUrlParameters();
            if (urlParameters != null && urlParameters.Length != 0)
            {
                var redirectUrl = "";
                var item = this.DynamicManager.Provider.GetItemFromUrl(this.DynamicContentType, this.GetUrlParameterString(true), out redirectUrl) as DynamicContent;
                if (item != null && item.GetType() == this.DynamicContentType)
                {
                    if (!String.IsNullOrEmpty(this.GetUrlParameterString(false)))
                    {
                        var matches = Regex.Matches(this.GetUrlParameterString(false), widgetNameRegularExpression);
                        if ((matches.Count == 1 && matches[0].Groups["urlPrefix"].Value == this.UrlKeyPrefix)
                            || (matches.Count == 0 && String.IsNullOrEmpty(this.UrlKeyPrefix)))
                        {
                            this.DetailItem = item;
                            RouteHelper.SetUrlParametersResolved();
                        }
                    }
                }
            }
        }

In the above method we simply set the DetailItem public property of our custom widget, which we are using in the ResolvePageTitle() to retrieve the item Title and work with it.

 

Finally our class should look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telerik.Sitefinity.DynamicModules.Web.UI.Frontend;
using Telerik.Sitefinity.Model;
using Telerik.Sitefinity.DynamicModules.Model;
using System.Text.RegularExpressions;
using Telerik.Sitefinity.Web;
using System.Web.UI;
 
namespace SitefinityWebApp
{
    public class DCVCustom : DynamicContentView
    {
 
        # region Properties
       
        public PageTitleModes PageTitleModeInternal { get; set; }
 
        public DynamicContent DetailItem { get; set; }
 
        /// <summary>
        /// Defines identifiers that indicate if and how the page title should be set.
        /// </summary>
        public enum PageTitleModes
        {
            /// <summary>
            /// Indicates that the page title should be replaced by the item title.
            /// </summary>
            Replace,
            /// <summary>
            /// Indicates that the page title should not be altered.
            /// </summary>
            DoNotSet,
            /// <summary>
            /// Indicates that the item title should be appended to the page title.
            /// </summary>
            Append
        };
 
        # endregion
 
        #region Methods
        
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            this.SetSingleItem();
            this.ResolvePageTitle();
        }
 
        protected virtual void ResolvePageTitle()
        {
            if (this.DetailItem == null || this.Page == null)
                return;
            if (this.PageTitleModeInternal == PageTitleModes.DoNotSet)
                return;
 
            DynamicContent cnt = this.DetailItem as DynamicContent;
 
            if (cnt == null)
                return;
 
            if (this.IsSingleItem())
            {
                var title = cnt.GetValue<String>("Title");
                switch (this.PageTitleModeInternal)
                {
                    case PageTitleModes.Append:
                        if (title != null)
                            this.Page.Title = String.Format("{0} {1}", this.Page.Title, title);
                        break;
                    case PageTitleModes.Replace:
                        if (title != null)
                            this.Page.Title = title;
                        else
                            this.Page.Title = "";
                        break;
                }
            }
        }
 
        protected void SetSingleItem()
        {
            if (this.DetailViewDefinition.DataItemId != Guid.Empty)
            {
                this.DetailItem = this.DynamicManager.GetDataItem(this.DynamicContentType, this.DetailViewDefinition.DataItemId);
            }
 
            var urlParameters = this.GetUrlParameters();
            if (urlParameters != null && urlParameters.Length != 0)
            {
                var redirectUrl = "";
                var item = this.DynamicManager.Provider.GetItemFromUrl(this.DynamicContentType, this.GetUrlParameterString(true), out redirectUrl) as DynamicContent;
                if (item != null && item.GetType() == this.DynamicContentType)
                {
                    if (!String.IsNullOrEmpty(this.GetUrlParameterString(false)))
                    {
                        var matches = Regex.Matches(this.GetUrlParameterString(false), widgetNameRegularExpression);
                        if ((matches.Count == 1 && matches[0].Groups["urlPrefix"].Value == this.UrlKeyPrefix)
                            || (matches.Count == 0 && String.IsNullOrEmpty(this.UrlKeyPrefix)))
                        {
                            this.DetailItem = item;
                            RouteHelper.SetUrlParametersResolved();
                        }
                    }
                }
            }
        }
 
        #endregion
 
        #region Constants
        private const string widgetNameRegularExpression = @"/!(?<urlPrefix>[a-zA-Z0-9_\-]+)/.*";
        #endregion
    }
}

 

For your convenience I'm attaching an archive of the class to this blog post - CustomDynamicContentView , so you can directly include it in your solution and use it.

 

As usual, a video is always helpful in getting the whole picture, so please find below one I've recorded for the purposes of this blog post:

 

I hope you found the blog post useful. Any comments and suggestions are highly appreciated.

CustomDynamicContentView

1 comment

Leave a comment
  1. Lian Lee Jul 24, 2012
    Nice post , but could you provide more information about the widget performance. 
          1. How many database queries it makes 
          2. How much time it takes to render a page with this widget without Open Access cache and output cache.
          3.  How it is going to perform if you have 20 widgets like this one ? 

    Leave a comment