Page Part Development

Author:JonK
Last Updated:August 29, 2017 1:32 PM

Page parts only have a display-side representation.  Because there is no editor, they either find their data from the current workstation document state or extract their data from static attributes.  Page parts can be either .ascx controls or compiled controls.  Currently Titan ships only with compiled controls.

Compiled page part controls are very similar to the display-side implementation of blocks.  They differ only in their method of initialization.  Because blocks are loaded directly by the content page part, when a block is created, the content page part can immediately call the InitializeCmsComponent method.  Page parts on the other hand are loaded into the page layout container control by .Net.  .Net doesn’t know how to initialize a page part with CMS data. Thus, page parts must take an active role in their own initialization. 

Sample Page Part Source Code
public class SamplePagePart : CmsComponentBase, IContentCmsComponent
{
    private string _myArgument = "Not Initialized" ;
    public string MyArgument
    {
        get { return _myArgument ; }
        set { _myArgument = value; }
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        LayoutController layout = FindLayoutController();
        if (layout != null)
            layout.InitializeMe(this);
    }

    private DisplayDocument _cmsDocument;
    public void InitializeCmsComponent(short appID, string applicationPath, string userName, string userPassword, int docID, DisplayDocument cmsDocument)
    {
        _cmsDocument = cmsDocument;
    }

    protected override void CmsRenderContents(HtmlTextWriter output)
    {
        output.Write("<h2>From Sample Page Part</h2>") ;
        output.Write("Control Argument: {0}<br />", _myArgument) ;
        output.Write("Something From Document: {0}<br />", _cmsDocument.DisplayName);
    }
}

Notes:

  • Like the display-side for a Block, SamplePagePart inherits CmsComponentBase.  CmsComponentBase is a required base class and is responsible for handling the Titan-specific initialization and rendering of the component. 
  • SamplePagePart implements the interface IContentCmsComponent.  This is similar to the IBlockCmsComponent interface implemented by the block’s display side. Whereas a block must implement IBlockCmsComponent, a page part can implement any of the interfaces listed below, but it must implement one. All of the interfaces require the implementation of the function, InitializeCmsComponent, to initialize the state of the control, although the arguments differ slightly.    Each interface passes a different set of state data to the implementing control.   
    • IBasicCmsComponent has the thinnest InitializeCmsComponent:
      • appID – required for most calls into the database
      • applicationPath – legacy argument.  Since Titan v4 does not support installation into a sub-application, this value will always be “/”
      • userLogin and userPassword – required for most calls into the database
      • docID – the current document ID
        • INavCmsComponent adds the site-specific default rootDocID to its version of InitializeCmsComponent
        • IContentCmsComponent adds a pointer to the DisplayDocument instance that is currently being processed
  • SamplePagePart exposes a public property, MyArgument.  Page parts are placed directly onto the PageLayout and public properties through their exposure as attributes are the normal means for the author of the PageLayout to provide additional configuration arguments. 
  • In the OnLoad event, the Page Part must locate its PageLayout container and ask the controller to send its initialization data.  This step is the primary programmatic difference between a page part and a block.  The initialization step for a block happens when the block is created by the content page part; the initialization for a page part happens when the page part loads and requests its data from the page layout. 
  • In this example, the InitializeCmsComponent call signature is determined by the IContentCmsComponent interface.  During this call, the page part stores off a pointer to the DisplayDocument for use during the rendering phase.
  • CmsRenderContents writes its HTML into the provided HtmlTextWriter, extracting some of its data from its properties and some of its data from the current DisplayDocument.

 

Deploy your page part by uploading your non-compiled pieces to its subdirectory in the Blocks directory.  Upload your DLL to the /bin/customerBin directory for both the workstation and the display.

 

Page Parts and Blocks

The similarity between the display-side for blocks and a page part is intentional.  In both cases, a version of InitializeCmsComponent is called that provides data to the component and the component then renders its content in CmsRenderContents.  The only difference is where the data comes from—either the block’s XML data or from public properties on the component. 

The What’s New block is an example of a block that also operates as a page part.  It implements both INavCmsComponent and IBlockCmsComponent.  When rendered as a block, the What’s New block lets the author change display and configuration settings as well as select the search root. On the other hand, when used as a page part, the page layout designer can only set the root docID and provide a title.  Creating one control that serves two purposes is a solution when only a small amount of configuration information is present and when the component can display correctly regardless of whether the data is changed with every page (set via author block configuration) or whether the data is the same across all pages (set via public properties on the control inside its page layout)

 

Page Part Development Best Practices
  • Don’t ignore performance.  Unlike blocks which may exist on only a handful of pages, a page part is executed with every use of its containing page layout.  Minimize your use of database calls.  If you are making expensive database calls, consider caching. 
  • If you need information from the display document do not read the display document from the database.  Instead, request it by choosing the IContentCmsComponent interface.
  • Follow the display design guidelines for blocks.  In particular, generate plain, unstyled HTML.
  • Minimize your scope.  If your page part will never be used as a block, don’t also make it a block.  

 

top