Supporting Mobile Devices with Microsoft Content Management Server 2002

Content Management Server
 

May 2003

Patrick Gaul
proAxent solutions inc.

Mike Henderlight
Microsoft Corporation

Applies to:
    Microsoft Content Management Server 2002
    Microsoft Mobile Internet Toolkit

Summary: Build Microsoft Content Management Server Web sites that can be browsed by mobile devices using the Microsoft Mobile Internet Toolkit. Review the examples in this document to learn the guidelines and approaches to building multiple—device support into an MCMS Web site. (34 printed pages).

Download a copy of this document from the Microsoft Download Center (http://go.microsoft.com/fwlink/?LinkId=16161).

Download a copy of this document from the MSDN Download Center.

Contents

Introduction
Design Considerations and Techniques
Walk—Through: A Mobile Web Form Project
Conclusion
Appendix—Automatic Posting Creation

Introduction

This document describes how to use the Microsoft® Mobile Internet Toolkit (MMIT) with Microsoft Content Management Server 2002 (MCMS) so you can build a MCMS Web site that supports browsing by mobile devices such as personal digital assistants (PDAs), Web phones, and other devices.

It describes design considerations and techniques you can use when planning for the use of mobile devices with the MMIT and MCMS. It then guides you through an example in which you create your own mobile Web form project.

This document assumes familiarity with Microsoft Content Management Server 2002, Microsoft Visual Studio® .NET, and the Visual C#® programming language.

About MMIT

The Microsoft Mobile Internet Toolkit (MMIT) provides a selection of controls which can accept content in various formats. Then, in real time, the MMIT dynamically renders the content in the markup format determined by the devices that access these mobile Web forms. You can download the MMIT from http://go.microsoft.com/fwlink/?linkid=16146.

Before the development of the MMIT, a site designer who wanted to implement templates for mobile devices would need to either develop alternate device—optimized templates which would render the content in the correct formats and layout per device, or embed all of the required functionality for all supported devices in each template. Either way this could represent a significant amount of work.

Through the use of the MMIT, this process has been simplified considerably. The MMIT further separates content from format by encapsulating content inside MMIT objects which are "wrapped" with the markup required by each browsing device. It also contains a server component which automatically detects the browsing device type and automatically selects the appropriate markup for that device. The MCMS site designer can employ MMIT Mobile Web Forms as MCMS templates to access MCMS content in real time.

Challenges of Content Delivery for Mobile Devices

The physical geometry of mobile devices introduces new challenges for content delivery. Not only are there often lower—bandwidth issues to consider, but designers must plan how to deploy content on smaller screens, in browser environments which usually possess limited client—side processing capabilities. For example, a designer may be initially inclined to make extensive use of Dynamic HTML features for structures like pop—up menus, tool—tips, floating windows, and so on. However, most mobile browsing environments do not possess these capabilities – therefore, simpler user interface features must be employed for these devices.

Many mobile devices (for example, WAP phones) require Web content to be presented in either WML or cHTML. The challenge in these situations is in deciding how to render the same physical content that was originally created for HTML environments using these alternate layouts – or indeed if it is required to allow the authoring of content from these devices.

Getting it All Together on a Mobile Device

All devices are not created equal. Before taking the approach that "all site management functions should be available from all devices," it is important to consider the following:

  • Rich content. In general, extensive rich—formatting of content (through the use of HTML) in MCMS placeholders is not appropriate for many types of mobile devices. When designing templates that contain content for mobile devices, the designer must bear these differences in mind. In many (if not most) cases, the best format for text content targeted to mobile devices is unformatted (plain) text.
  • Graphics. Care must be taken in the use of graphics for mobile devices. Often these devices are accessing the internet via wireless connections which may be of low bandwidth, so the embedding of large graphic objects will affect download performance. Graphic rendering capabilities of the target device must also be taken into account. Embedding graphic objects that will not be rendered in targeted devices should be avoided.
  • Variations in Device Capabilities. There is considerable variation (and inconsistency) in the functional capabilities of devices. It is often difficult to select a common subset of capabilities to support or exploit if a wide range of device types is considered. This is less of an issue in supporting content browsing than for content creation and update, as the latter must access a wider range of user interface features on the mobile device.
  • Screen "Real Estate". Because of the more restricted screen displays available on most mobile devices – as well as possible bandwidth issues – it may be appropriate to configure the content authoring environment with placeholders specifically intended for "mobile" content. For example, perhaps a news organization publishes detailed news articles on their site. For mobile devices it may be required to have separate placeholders for "condensed" versions of the content that will be more easily accommodated by mobile devices.
  • Navigation Constraints. In designing MCMS Web sites for HTML browsers, it is common practice to incorporate navigation components with capabilities like:
    • Dynamic HTML pop—up menus
    • Graphic buttons for common links, with rollover effects
    • Dynamic site maps that employ HTML TABLE structures to control indentation
    • Extensive summary lists of postings with selected content elements from those postings.

    While some of these items pose no problem for many mobile devices (for example, summary lists), some may not be possible at all (for example, Graphic rollovers and DHTML on a WAP device). And with mobile devices it may yet be required to condense long summary lists to minimize the amount of scrolling needed to locate a particular item.

    In general, navigational elements compete with content for screen space – and nowhere more so than on mobile devices. When targeting small screens it is often necessary to minimize the amount of navigation displayed on any given screen, and use dedicated navigation pages to present more extensive navigation lists to the subscribing user.

  • Content Management Infrastructure. The MCMS Web Author not only allows for direct editing of content through a desktop browser, but also provides comprehensive support for the various publishing functions and events via the Web Author Console. The sample Web Author Console that ships with MCMS is dependent on use in HTML templates and cannot be directly added to a Mobile Web Form. The standard Web Author interface also makes extensive use of client—side JavaScript functionality, which may not be available on a mobile device.

    In actual practice, mobile devices often do not offer optimal environments on which to base comprehensive content management capabilities. Rather it is more likely that if your organization does identify the need for mobile devices to create, change, or submit content, the scope of this role will be limited. It is relatively simple to build custom controls that can enable the submitting of content to MCMS from a mobile device, and if your organization can agree on a suitably limited role for the submission of content from these devices, the amount of work involved in developing these controls can be kept to a manageable minimum.

    This issue will be discussed later in this document under "Mobile Device Usage Scenarios".

Design Considerations and Techniques

The previous section of this document presented a number of issues to consider when planning for the use of mobile devices with the MMIT and MCMS. This section outlines design considerations and techniques that you can employ to support these devices.

Content Creation

A standard feature of MCMS 2002 is the Web Author, an interface that requires Microsoft Internet Explorer 5.5 or later. Because of this requirement, the default primary authoring mechanism for MCMS is the desktop—based Internet Explorer environment.

The Web Author is a rich environment for the creation and management of content in MCMS. It includes WYSIWYG editing of formatted HTML objects, as well as access to all publishing events such as Save, Submit, Approve, Decline, and Delete. All properties for published content items can be manipulated through this interface via the Web Author Console.

The Web Author is completely customizable and extensible. This extensibility arises as a result of the fact that the Web Author is entirely built upon the MCMS Publishing API. In addition to its extensive applicability in designing navigation and other common site features, the MCMS Publishing API can also be employed to:

  • Allow the programmatic creation and management of content from other sources (for example, news feeds, XML Web Services, and database applications)
  • Allow the creation of alternate editing environments that use other browsers.

MCMS content is stored in placeholders, which are rendered dynamically both when editing and browsing content. When the subscribing user browses an MCMS page, a placeholder embedded within an MCMS template simply emits its content at the placeholder's physical location within the template layout. When an authorized user enters edit mode on the template, the MCMS Web Author automatically switches the placeholder into editing mode, which supports the direct editing of content in the placeholder's location on the template.

Placeholders can contain HTML or XML. Rich editing of HTML content is enabled without any need for customization; direct editing of XML content requires the use of custom controls that render editing forms for elements of the XML schema stored within the XML placeholder.

An issue arises when content stored in an MCMS placeholder is to be accessed from an MMIT Mobile Web Form – the placeholder cannot be directly embedded on the Mobile Web Form, but must be accessed programmatically.

The Web controls introduced by MCMS 2002 and the MMIT have a common origin in the .NET Framework, as indicated in the following figure.

Figure 1. Web controls arrangement

As illustrated in this figure, the MCMS placeholder control is derived from the System.Web.UI.WebControls.WebControl class, which is in turn derived from the System.Web.UI.Control class. System.Web.UI.MobileControls is also derived from the System.Web.UI.Control class. What this means to MCMS site designers is that it is not possible to place an MCMS placeholder on a Mobile Web Form. This has the following implications:

  • On a Mobile Web Form, content must be attached to mobile controls through the use of the MCMS Publishing API.
  • Direct editing of content from a Mobile Web Form cannot be done through an MCMS placeholder control, but instead must be done through the use of Mobile Web Form controls.

Fortunately, this is a relatively simple process to enable in Mobile Web Forms. In this document, examples will be presented that show how to accomplish this task.

Mobile Device Usage Scenarios

Before implementing mobile device support on your MCMS site, you must precisely define the role that mobile devices will have.

The following table presents a progressive summary of the scenarios that you can implement, and the implications of each in site customization and design.

Table 1.

Mobile device role Content authoring Customization required Comments
Browse—only Exclusively done via the desktop—based MCMS Web Author or external programs using the MCMS Publishing API
  • Develop standard HTML—browser—based templates
  • Develop Mobile Web Form templates for browsing
  • Most common implementation.
  • No custom Web Author development required.
  • Mobile device browsing can be to dedicated MCMS channels or to the content's original channel employing template switching.
Browsing with limited content update All original content pages are created via the Web Author or external programs using the MCMS Publishing API
  • Develop standard HTML—browser—based templates for primary authoring
  • Develop Mobile Web Form templates with limited update capabilities
  • Modify MMIT Device Adapter to correctly handle postback events for MCMS
  • Publishing workflow remains within the standard Web Author (desktop Internet Explorer)
  • MMIT Mobile Web Forms must operate in two modes: Presentation and Edit
  • Custom editing logic required for Mobile Web Forms
Full content creation and maintenance Content can be authored via standard Web Author, Mobile Devices, and external programs using the MCMS Publishing API
  • Develop standard HTML—browser—based templates for primary authoring
  • Develop Mobile Web Form templates with complete content creation and management capabilities
  • Modify MMIT Device Adapter to correctly handle postback events for MCMS
  • This scenario requires the most work, since a Mobile Web Form—based Web Author console must be built to include all required Web Author functions (Create, Update, Submit, Approve, Decline, Delete)
  • Comments as for "limited content update" (above) also apply.

All three scenarios in the above table are feasible through the use of the MMIT and the MCMS Publishing API. In practical terms, the most common application of this technology uses the first ("Browse—only") scenario. This document will illustrate an example of the second ("Browsing with limited content update") scenario, which encapsulates the first, and provides a base on which you can implement the more comprehensive third scenario if required.

Publishing Content for Mobile Access

An important consideration in designing your site for use with multiple devices is deciding where content will reside to support your requirements. There are two basic options, each with its own advantages and drawbacks; you must decide which option is more suitable for your site:

  • Single Channel Structure with Device—Driven Template Switching: Under this option, there is one single channel structure for the site. The templates used to post content will contain a function to detect the browsing device type. If the site is viewed from a standard HTML browser such as Internet Explorer, content is rendered with the original HTML template used to publish the content. If it is viewed using a mobile device, template switching may be employed to dynamically switch to a Mobile Web Form template.

    This option is most suitable if it is desired that the entire site be commonly accessible by both standard HTML browsers as well as mobile devices. Using this option has the advantage that no multiple postings of content (through MCMS connected pages) are required.

    A potential drawback to this approach is that it is less efficient than direct invocation of the desired template, since before rendering the Mobile Web Form, the original template must be loaded by the server in order to redirect to the alternate template.

  • Dedicated Mobile Device Channels: In this scenario, content will be authored in one channel location designed for use with the standard MCMS Web Author and browsed by standard HTML browsers. For mobile devices, connected postings will be created (either manually or automatically) in another channel location. These connected postings will be published using MMIT Mobile Web Form connected templates. In MCMS 2002, connected templates are two or more templates that share a common MCMS Template Gallery Item (TGI) – and consequently share that TGI's placeholders.

    The main advantage of this approach over template switching is improved performance; the mobile device user will navigate directly to each Mobile Web Form without requiring the server to redirect to a template—switched URL first.

    The principal drawback to this option is increased site schema, with more postings to manage for a given piece of content.

    If you are to create postings in a mobile channel manually, you must build the required Web Author functionality into your Mobile Web Form templates – including Web Author Console functions. For the same reason that a MCMS placeholder control cannot be embedded in a Mobile Web Form, you cannot do likewise with a normal MCMS Web Author Console. Otherwise, an attempt to create a connected posting in the Web Author will take the author to a Web form without any means of saving or submitting the posting for publication.

The example code in this document will use the first option: template switching. For automatic creation of connected postings in a separate channel, an example of the required logic can be found in "Appendix – Automatic Posting Creation".

About Testing Mobile Web Forms

In order to fully test your Mobile Web Forms, you will need either a network—connected mobile device with a Web browser (HTML, WML, or cHTML), or a device emulator. Screen shots seen later in this document were taken from the device emulator contained within the Microsoft Pocket PC 2002 SDK (available from http://go.microsoft.com/fwlink/?linkid=16147). There are other third—party emulators available on the Web.

You can also browse your Mobile Web Form using a standard HTML browser, such as Internet Explorer.

Walk—Through: A Mobile Web Form Project

As an example of building a project containing support for mobile forms, this document will walk through the creation of a Web project in Visual Studio .NET. Before starting this process, you must ensure that:

  1. You have a working development environment for Microsoft Content Management Server (MCMS) 2002. Consult the MCMS 2002 installation documentation for more details.
  2. You have installed the WoodgroveNet sample (for C# users) from the MCMS 2002 installation CD – or the WoodgroveNetVB sample (for Visual Basic.NET users) available for download from http://go.microsoft.com/fwlink/?LinkId=17402. This will ensure that you already have channels, templates, and content in your MCMS system.
  3. You have configured MCMS guest access in the MCMS Server Configuration Application (SCA), and you have added the MCMS Guest User Account to a guest subscriber group via the MCMS Site Manager.
  4. You have installed the Microsoft Mobile Internet Toolkit. If you haven't installed the toolkit yet, you can download it from http://go.microsoft.com/fwlink/?linkid=16146.

The Process

The example in this document will proceed through the following major steps:

  1. Creating Navigation Controls – You will create four custom composite controls for creating navigation, login/logout, and an edit link in your Mobile Web Form. Another control will be created for your regular (non—mobile) Web Form templates that will enable template switching.
  2. Modifying WoodgroveNet – You will make a change to the sample WoodgroveNet project to enable the Job Posting template to dynamically switch to the mobile template you define in the next step.
  3. Creating the MobileCMS Project – You will create a project to contain your mobile Web forms. In this project you will build and test a Mobile Web Form version of the WoodgroveNet Job Posting template.
  4. Adding Content Update Capability – You will change the Job Posting Mobile Web Form to allow the user to log in and subsequently edit content.

Creating Navigation Controls

As with any MCMS template, your mobile templates will need basic navigation components. However, in most cases, mobile devices have significant constraints in both screen real estate and connection bandwidth. It is therefore important that:

  • Navigation should be kept simple and concise. While it may be aesthetically pleasing to create elaborate navigation designs (for example, using many graphical elements), this may compromise performance on mobile devices.
  • Page layouts should contain only the required navigational elements. It's not necessary for every mobile page to include a full set of links to every channel or posting. Instead, it may be more efficient to create separate "navigation pages" for each channel, and each content page should be able to link back to those pages.

In this section you will create two navigation controls for use with your Mobile Web Forms:

  • Breadcrumb: This control is suitable for use on most (if not all) pages, and will provide a navigation path from the current location back to the root channel.
  • Posting and Channel List: This control will create lists of postings and sub—channels within a channel. It is most likely that you will use this control only on the previously—mentioned "navigation pages", otherwise the navigation may occupy a significant amount of space on each page, particularly if there are many postings and/or sub—channels.

In addition, the steps that follow will create two additional controls for use later in this process for an example of content editing:

  • Login/Logout Link: This control renders a link to a separate Mobile Web Form to log in or log out as an authenticated user.
  • Edit Link: This control renders a hyperlink which will switch the current Mobile Web Form into editing mode.

The controls in this example are created as composite server controls, for maximum flexibility when using the controls in multiple projects.

The MobileNavControls Project

In this section you will create and compile a Mobile Web Form Control Library that you will use in creating your MCMS Mobile Web Forms.

From your development computer's desktop, start Microsoft Visual Studio .NET Interactive Development Environment (IDE) and perform the following steps:

  1. From the New Project Dialog, under Project Types, select either Visual Basic Projects or Visual C# Projects, depending on your preference for programming language. (Don't press Enter or click OK yet.)
  2. Under Templates select Web Control Library. (Don't press Enter or click OK yet.)
  3. In the Name box change the name to MobileNavControls. Click OK.
  4. You will now be in the code view for WebCustomControl1. Close this window.
  5. In the Solution Explorer, right—click WebCustomControl1, and then select Delete. Click OK to confirm the deletion.
  6. Add the following assembly references to your project (right click References and select Add Reference...):
    • Microsoft.ContentManagement.Publishing.dll (found under \Program Files\Microsoft Content Management Server\Server\bin).
    • System.Web.Mobile.dll (should appear on the .NET tab of the Add Reference dialog).

The Breadcrumb Control

The MobileBreadcrumb control will be used to render a hyperlink breadcrumb trail for navigation.

  1. In the Solution Explorer, right—click MobileNavControls, click Add, and then click Add New Items.
  2. In the Local Project Items category, select the Web Custom Control template. (Don't press Enter or click Open yet.)
  3. In the Name box, type MobileBreadCrumb. Click Open.
  4. Select all code in this window (Ctrl—A) and press the Delete key.
  5. Enter the following code into the MobileBreadcrumb code edit view:

Visual C#

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web.Mobile;
using System.Web.UI.MobileControls;
using Microsoft.ContentManagement.Publishing;

namespace MobileNavControls
{
    /// <summary>
    /// Render breadcrumb trail to current posting
    /// on a Mobile Web Form.
    /// </summary>
     [DefaultProperty("SeparatorText"), 
    ToolboxData("<{0}:MobileBreadcrumb runat=server></{0}:MobileBreadcrumb>")]
    public class MobileBreadcrumb : MobileControl
    {
        private string text;
    
        [Bindable(true),
        Category("Appearance")]
        public string SeparatorText
        {
            get
            {
                return text;
            }

            set
            {
                text = value;
            }
        }

        protected CmsHttpContext cxhCms;
        protected Posting poCurrent;
        protected Channel chCurrent;
        protected string strPostingGuid;
        protected BooleanOption blnMobileTrue = BooleanOption.True;
        protected BooleanOption blnMobileFalse = BooleanOption.False;

        protected override void CreateChildControls()
        {
            //Call base class
            base.CreateChildControls();

            // Get the MCMS Http context
            cxhCms = CmsHttpContext.Current;

            // Check if POSTINGGUID is specified.  If
            // so, we've been template-switched.
            strPostingGuid = base.Page.Request.QueryString["POSTINGGUID"];
            if (strPostingGuid != null)
            {
                poCurrent = (Posting)cxhCms.Searches.GetByGuid(strPostingGuid);
                chCurrent = poCurrent.Parent;
            }
            else
            {
                poCurrent = cxhCms.Posting;
                chCurrent = cxhCms.Channel;
            }
            Panel pnlBreadcrumb = new Panel();
            pnlBreadcrumb.BreakAfter = true;

            BreadcrumbTrail(chCurrent, pnlBreadcrumb);
            Controls.Add(pnlBreadcrumb);
        }

        /// <summary>
        /// Recursive function to render breadrumb trail to root channel.
        /// </summary>
        /// <param name="ciChannelItem">Channel or posting item</param>
        /// <param name="pnlPanel">Mobile Web form panel to add 
        /// breadcrumb trail to.</param>
        protected void BreadcrumbTrail(ChannelItem ciChannelItem, Panel pnlPanel)
        {
            // Immediately recurse upwards if we're not at the root channel yet.
            if (ciChannelItem.Parent != null)
            {
                BreadcrumbTrail(ciChannelItem.Parent, pnlPanel);
            }

            // We don't want to render a link to the current item,
            // only its parents.
            if (!ciChannelItem.Equals(cxhCms.ChannelItem))
            {
                // Create a new link control. 
                Link lnkParentLink = new Link();
                lnkParentLink.NavigateUrl = ciChannelItem.UrlModePublished + 
                "?MSWITCH=Y";
                lnkParentLink.Font.Bold = blnMobileTrue;
                lnkParentLink.Font.Size = (FontSize)FontSize.Normal;
                lnkParentLink.Wrapping = Wrapping.Wrap;
                lnkParentLink.BreakAfter = false;

                // Add a link separator.
                Label lblSeparator = new Label();
                if (ciChannelItem.Parent != null)
                {
                    lblSeparator.Text = SeparatorText;
                    lblSeparator.Font.Bold = blnMobileTrue;
                    lblSeparator.Wrapping = Wrapping.Wrap;
                    lblSeparator.BreakAfter = false;
                    pnlPanel.Controls.Add(lblSeparator);
                    lnkParentLink.Text = ciChannelItem.DisplayName;
                }
                else
                {
                    // We'll use the name "Home" for the root channel,
                    // instead of "Channels".
                    lnkParentLink.Text = "Home";
                }
                pnlPanel.Controls.Add(lnkParentLink);
            }
        }
    }
}

Visual Basic.NET

Imports System
Imports System.Web.UI
Imports System.ComponentModel
Imports System.Web.Mobile
Imports System.Web.UI.MobileControls
Imports Microsoft.ContentManagement.Publishing

<DefaultProperty("SeparatorText"), _
ToolboxData("<0:MobileBreadcrumb runat=server></0:MobileBreadcrumb>")> _
Public Class MobileBreadcrumb
   Inherits MobileUserControl

   Dim _text As String

   <Bindable(True), Category("Appearance"), DefaultValue("")> _
   Property SeparatorText() As String
      Get
         Return _text
      End Get

      Set(ByVal Value As String)
         _text = Value
      End Set
   End Property

   Protected cxhCms As CmsHttpContext
   Protected poCurrent As Posting
   Protected chCurrent As Channel
   Protected strPostingGuid As String
   Protected blnMobileTrue As BooleanOption = BooleanOption.True
   Protected blnMobileFalse As BooleanOption = BooleanOption.False

   Protected Overrides Sub CreateChildControls()
      Dim pnlBreadcrumb As Panel = New Panel()

      'Call base class
      MyBase.CreateChildControls()

      ' Get the MCMS Http context
      cxhCms = CmsHttpContext.Current

      ' Check if POSTINGGUID is specified.  If
      ' so, we've been template-switched.
      strPostingGuid = Request.QueryString("POSTINGGUID")

      If strPostingGuid <> Nothing Then
         poCurrent = cxhCms.Searches.GetByGuid(strPostingGuid)
         chCurrent = poCurrent.Parent
      Else
         poCurrent = cxhCms.Posting
         chCurrent = cxhCms.Channel
      End If
      pnlBreadcrumb.BreakAfter = True

      BreadcrumbTrail(chCurrent, pnlBreadcrumb)
      Controls.Add(pnlBreadcrumb)
   End Sub

   ' <summary>
   ' Recursive function to render breadrumb trail to root channel.
   ' </summary>
   ' <param name="ciChannelItem">Channel or posting item</param>
   ' <param name="pnlPanel">Mobile Web form panel to add _
   'breadcrumb trail to.</param>
   Protected Sub BreadcrumbTrail(ByVal ciChannelItem As ChannelItem, _
   ByVal pnlPanel As Panel)

      ' Immediately recurse upwards if we're not at the root channel yet.
      If Not ciChannelItem.Parent Is Nothing Then
         BreadcrumbTrail(ciChannelItem.Parent, pnlPanel)
      End If

      ' We don't want to render a link to the current item,
      ' only its parents.
      If Not ciChannelItem.Equals(cxhCms.ChannelItem) Then

         ' Create a new link control. 
         Dim lnkParentLink As New Link()
         lnkParentLink.NavigateUrl = ciChannelItem.UrlModePublished + _
         "?MSWITCH=Y"
         lnkParentLink.Font.Bold = blnMobileTrue
         lnkParentLink.Font.Size = FontSize.Normal
         lnkParentLink.Wrapping = Wrapping.Wrap
         lnkParentLink.BreakAfter = False

         ' Add a link separator.
         Dim lblSeparator = New Label()
         If Not ciChannelItem.Parent Is Nothing Then
            lblSeparator.Text = SeparatorText
            lblSeparator.Font.Bold = blnMobileTrue
            lblSeparator.Wrapping = Wrapping.Wrap
            lblSeparator.BreakAfter = False
            pnlPanel.Controls.Add(lblSeparator)
            lnkParentLink.Text = ciChannelItem.DisplayName
         Else
            ' We'll use the name "Home" for the root channel,
            ' instead of "Channels".
            lnkParentLink.Text = "Home"
         End If
         pnlPanel.Controls.Add(lnkParentLink)
      End If
   End Sub
End Class

This control works by dynamically adding Link control objects to a Mobile Web Form Panel object. For each link, the Query String parameter "MSWITCH=Y" is appended to the link's URL to request switching. This is done for the purposes of testing from a non—mobile device (such as Internet Explorer on your desktop).

The Posting and Channel List Control

The MobileNavList control will be used to render lists of hyperlinks to other postings and sub—channels in the current channel.

  1. In the Local Project Items category, select the Web Custom Control template. (Don't press Enter or click Open yet.)
  2. In the Name box, type MobileNavList. Click Open.
  3. Select all code in this window (Ctrl—A) and press the Delete key.
  4. Enter the following code into the MobileNavList code edit view:

Visual C#

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web.Mobile;
using System.Web.UI.MobileControls;
using Microsoft.ContentManagement.Publishing;

namespace MobileNavControls
{
    /// <summary>
    /// Render lists of links to other postings and
    /// sub-channels in the current channel on a
    /// Mobile Web Form.
    /// </summary>
    [DefaultProperty("Text"), 
    ToolboxData("<{0}:MobileNavList runat=server></{0}:MobileNavList>")]
    public class MobileNavList : MobileControl
    {
        private string text;

        [Bindable(true),
        Category("Appearance")]
        public string SeparatorText
        {
            get
            {
                return text;
            }

            set
            {
                text = value;
            }
        }
        protected CmsHttpContext cxhCms;
        protected Posting poCurrent;
        protected Channel chCurrent;
        protected string strPostingGuid;
        protected BooleanOption blnMobileTrue = BooleanOption.True;
        protected BooleanOption blnMobileFalse = BooleanOption.False;
                
        protected override void CreateChildControls()
        {
            //Call base class
            base.CreateChildControls();
            
            // Get the MCMS Http context
            cxhCms = CmsHttpContext.Current;

            // Check if POSTINGGUID is specified.  If
            // so, we've been template-switched.
            strPostingGuid = base.Page.Request.QueryString["POSTINGGUID"];
            if (strPostingGuid != null)
            {
                poCurrent = (Posting)cxhCms.Searches.GetByGuid(strPostingGuid);
                chCurrent = poCurrent.Parent;
            }
            else
            {
                poCurrent = cxhCms.Posting;
                chCurrent = cxhCms.Channel;
            }
            Panel pnlPostingList = new Panel();
            Panel pnlChannelList = new Panel();
            pnlPostingList.BreakAfter = true;
            pnlChannelList.BreakAfter = true;

            PostingList(chCurrent, pnlPostingList, false);
            SubChannelList(chCurrent, pnlChannelList, false);
            Controls.Add(pnlPostingList);
            Controls.Add(pnlChannelList);
        }

        /// <summary>
        /// Renders a list of links to postings contained within a channel object.
        /// </summary>
        /// <param name="chnChannel">Channel item.</param>
        /// <param name="pnlPanel">Panel to which posting links are added.</param>
        /// <param name="blnBreakAfter">Whether or not to add line 
        /// breaks after each link.</param>
        protected void PostingList(Channel chnChannel, Panel pnlPanel, 
bool blnBreakAfter)
        {
            PostingCollection pcPostings = chnChannel.Postings;
            int intPostings = pcPostings.Count;
            int intPostCount = 0;
            foreach (Posting poPosting in pcPostings)
            {
                // Do not render links for postings called "Default" or
                // the current posting object.
                if ((poPosting.Name.ToLower() != "default")
                    & !poPosting.Equals(poCurrent))
                {
                    // Create a new link control. 
                    intPostCount++;
                    Link lnkPostingLink = new Link();
                    lnkPostingLink.Text = poPosting.DisplayName;
                    lnkPostingLink.NavigateUrl = poPosting.UrlModePublished + 
"?MSWITCH=Y";
                    lnkPostingLink.Font.Bold = blnMobileFalse;
                    lnkPostingLink.Font.Size = (FontSize)FontSize.Small;
                    lnkPostingLink.Wrapping = Wrapping.Wrap;
                    lnkPostingLink.BreakAfter = blnBreakAfter;
                    if ((intPostCount > 1) & (!blnBreakAfter))
                    {
                        // Add a link separator.
                        System.Web.UI.MobileControls.Label 
lblSeparator = new Label();
                        lblSeparator.Text = SeparatorText;
                        lblSeparator.Font.Bold = blnMobileFalse;
                        lblSeparator.Wrapping = Wrapping.Wrap;
                        lblSeparator.BreakAfter = false;
                        pnlPanel.Controls.Add(lblSeparator);
                    }
                    pnlPanel.Controls.Add(lnkPostingLink);
                }
            }
        }

        /// <summary>
        /// Renders a list of links to Sub-channels contained within 
a channel object.
        /// </summary>
        /// <param name="chnChannel">Channel item.</param>
        /// <param name="pnlPanel">Panel to which posting links are 
added.</param>
        /// <param name="blnBreakAfter">Whether or not to add line 
        /// breaks after each link.</param>
        protected void SubChannelList(Channel chnChannel, Panel pnlPanel, 
bool blnBreakAfter)
        {
            ChannelCollection ccChannels = chnChannel.Channels;
            int intChannels = ccChannels.Count;
            int intChanCount = 0;
            foreach (Channel chnSubChannel in ccChannels)
            {
                // Create a new link control. 
                intChanCount++;
                Link lnkChannelLink = new Link();
                lnkChannelLink.Text = chnSubChannel.DisplayName;
                lnkChannelLink.NavigateUrl = chnSubChannel.UrlModePublished + 
"?MSWITCH=Y";
                lnkChannelLink.Font.Bold = blnMobileTrue;
                lnkChannelLink.Font.Size = (FontSize)FontSize.Small;
                lnkChannelLink.Wrapping = Wrapping.Wrap;
                lnkChannelLink.BreakAfter = blnBreakAfter;
                if ((intChanCount > 1) & (blnBreakAfter == false))
                {
                    // Add a link separator.
                    Label lblSeparator = new Label();
                    lblSeparator.Text = SeparatorText;
                    lblSeparator.Font.Bold = blnMobileFalse;
                    lblSeparator.Wrapping = Wrapping.Wrap;
                    lblSeparator.BreakAfter = false;
                    lblSeparator.Font.Size = (FontSize)FontSize.Small;
                    pnlPanel.Controls.Add(lblSeparator);
                }
                pnlPanel.Controls.Add(lnkChannelLink);
            }
        }

    }
}

Visual Basic.NET

Imports System
Imports System.Web.UI
Imports System.ComponentModel
Imports System.Web.Mobile
Imports System.Web.UI.MobileControls
Imports Microsoft.ContentManagement.Publishing

<DefaultProperty("Text"), ToolboxData("<{0}:MobileNavList _ 
runat=server></{0}:MobileNavList>")> _
Public Class MobileNavList
   Inherits MobileUserControl

   Dim _text As String

   <Bindable(True), Category("Appearance"), DefaultValue("")> _
   Property [SeparatorText]() As String
      Get
         Return _text
      End Get

      Set(ByVal Value As String)
         _text = Value
      End Set
   End Property

   Protected cxhCms As CmsHttpContext
   Protected poCurrent As Posting
   Protected chCurrent As Channel
   Protected strPostingGuid As String
   Protected blnMobileTrue As BooleanOption = BooleanOption.True
   Protected blnMobileFalse As BooleanOption = BooleanOption.False

   Protected Overrides Sub CreateChildControls()
      'Call base class
      MyBase.CreateChildControls()

      ' Get the MCMS Http context
      cxhCms = CmsHttpContext.Current

      ' Check if POSTINGGUID is specified.  If
      ' so, we've been template-switched.
      strPostingGuid = Page.Request.QueryString("POSTINGGUID")
      If strPostingGuid <> "" Then
         poCurrent = cxhCms.Searches.GetByGuid(strPostingGuid)
         chCurrent = poCurrent.Parent
      Else
         poCurrent = cxhCms.Posting
         chCurrent = cxhCms.Channel
      End If

      Dim pnlPostingList As New Panel()
      Dim pnlChannelList As New Panel()
      pnlPostingList.BreakAfter = True
      pnlChannelList.BreakAfter = True

      PostingList(chCurrent, pnlPostingList, False)
      SubChannelList(chCurrent, pnlChannelList, False)
      Controls.Add(pnlPostingList)
      Controls.Add(pnlChannelList)
   End Sub

   ' Renders a list of links to postings contained within a channel object.
   Protected Sub PostingList(ByVal chnChannel As Channel, _
   ByVal pnlPanel As Panel, ByVal blnBreakAfter As Boolean)
      Dim pcPostings As PostingCollection = chnChannel.Postings
      Dim poPosting As Posting
      Dim intPostings As Integer = pcPostings.Count
      Dim intPostCount As Integer = 0
      For Each poPosting In pcPostings
         ' Do not render links for postings called "Default" or
         ' the current posting object.
         If (poPosting.Name.ToLower() <> "default") _
            And Not (poPosting.Equals(poCurrent)) Then
            intPostCount += 1
            ' Create a new link control. 
            Dim lnkPostingLink As New Link()
            lnkPostingLink.Text = poPosting.DisplayName
            lnkPostingLink.NavigateUrl = poPosting.UrlModePublished _
            + "?MSWITCH=Y"
            lnkPostingLink.Font.Bold = blnMobileFalse
            lnkPostingLink.Font.Size = FontSize.Small
            lnkPostingLink.Wrapping = Wrapping.Wrap
            lnkPostingLink.BreakAfter = blnBreakAfter
            If (intPostCount > 1) And Not (blnBreakAfter) Then
               ' Add a link separator.
               Dim lblSeparator As New System.Web.UI.MobileControls.Label()
               lblSeparator.Text = SeparatorText
               lblSeparator.Font.Bold = blnMobileFalse
               lblSeparator.Wrapping = Wrapping.Wrap
               lblSeparator.BreakAfter = False
               pnlPanel.Controls.Add(lblSeparator)
            End If
            pnlPanel.Controls.Add(lnkPostingLink)
         End If
      Next
   End Sub

   ' Renders a list of links to Sub-channels contained within _
   ' a channel object.
   Protected Sub SubChannelList(ByVal chnChannel As Channel, _
   ByVal pnlPanel As Panel, ByVal blnBreakAfter As Boolean)
      Dim ccChannels As ChannelCollection = chnChannel.Channels
      Dim chnSubChannel As Channel
      Dim intChannels As Integer = ccChannels.Count
      Dim intChanCount As Integer = 0
      For Each chnSubChannel In ccChannels
         ' Create a new link control. 
         intChanCount += 1
         Dim lnkChannelLink As New Link()
         lnkChannelLink.Text = chnSubChannel.DisplayName
         lnkChannelLink.NavigateUrl = chnSubChannel.UrlModePublished _
         + "?MSWITCH=Y"
         lnkChannelLink.Font.Bold = blnMobileTrue
         lnkChannelLink.Font.Size = FontSize.Small
         lnkChannelLink.Wrapping = Wrapping.Wrap
         lnkChannelLink.BreakAfter = blnBreakAfter
         If (intChanCount > 1) And Not (blnBreakAfter) Then
            ' Add a link separator.
            Dim lblSeparator As New Label()
            lblSeparator.Text = SeparatorText
            lblSeparator.Font.Bold = blnMobileFalse
            lblSeparator.Wrapping = Wrapping.Wrap
            lblSeparator.BreakAfter = False
            lblSeparator.Font.Size = FontSize.Small
            pnlPanel.Controls.Add(lblSeparator)
         End If
         pnlPanel.Controls.Add(lnkChannelLink)
      Next
   End Sub
End Class

As with the MobileBreadcumb control, this control works by dynamically adding Link control objects to a Mobile Web Form Panel object. For each link, the Query String parameter "MSWITCH=Y" is appended to the link's URL to request switching. This is done for the purposes of testing from a non—mobile device (such as Internet Explorer on your desktop).

In the CreateChildControls override method above, note that you can change the final argument in the PostingList and ChannelList function calls to true to insert line breaks between links instead of separator characters.

The Login/Logout Link Control

The MobileLoginLogout control will be used to render a login or logout hyperlink on the Mobile Web Form. This control will reference two template Web Forms which you will create later in this document (MobileLogin.aspx and MobileLogout.aspx in the section on "Adding Content Update Capability".

  1. In the Local Project Items category, select the Web Custom Control template. (Don't press Enter or click Open yet.)
  2. In the Name box, type MobileLoginLogout. Click Open.
  3. Select all code in this window (Ctrl—A) and press the Delete key.
  4. Enter the following code into the MobileLoginLogout code edit view:

Visual C#

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web.Mobile;
using System.Web.UI.MobileControls;
using Microsoft.ContentManagement.Publishing;

namespace MobileNavControls
{
    /// <summary>
    /// Render a Login/Logout link on a Mobile Web Form.
    /// </summary>
    [DefaultProperty("LoginUrl"), 
    ToolboxData("<{0}:MobileLoginLogout runat=server></{0}:MobileLoginLogout>")]
    public class MobileLoginLogout : MobileControl
    {
        private string logoutUrl;
        private string loginUrl;
    
        public string LogoutUrl
        {
            get { return logoutUrl; }
            set { logoutUrl = value; }
        }

        public string LoginUrl
        {
            get { return loginUrl; }
            set { loginUrl = value; }
        }

        protected CmsHttpContext cxhCms;
        protected Posting poCurrent;
        protected Channel chCurrent;
        protected string strPostingGuid;

        protected override void CreateChildControls()
        {
            Link lnkLoginLink = new Link();
            Panel pnlLogin = new Panel();
            
            //Call base class
            base.CreateChildControls();
            
            // Get the MCMS Http context
            cxhCms = CmsHttpContext.Current;

            // Check if POSTINGGUID is specified.  If
            // so, we've been template-switched.
            strPostingGuid = base.Page.Request.QueryString["POSTINGGUID"];
            if (strPostingGuid != null)
            {
                poCurrent = (Posting)cxhCms.Searches.GetByGuid(strPostingGuid);
                chCurrent = poCurrent.Parent;
            }
            else
            {
                poCurrent = cxhCms.Posting;
                chCurrent = cxhCms.Channel;
            }

            string strCurrentGuid = poCurrent.Guid;
            string sQueryString = poCurrent.QueryString;
            if (sQueryString == null)
            {
                sQueryString = "CURRENTGUID=" + strCurrentGuid + "&MSWITCH=Y";
            }
            else
            {
                sQueryString = sQueryString + "&CURRENTGUID=" + strCurrentGuid;
            }
            if (cxhCms.IsLoggedInAsGuest)
            {
                lnkLoginLink.Text = "Login";
                lnkLoginLink.NavigateUrl = LoginUrl + 
"?CURRENTGUID=" + strCurrentGuid;
            } 
            else
            {
                string strClientUserName = cxhCms.User.ClientAccountName;
                string strUserName = _
strClientUserName.Substring(strClientUserName.LastIndexOf
("/") + 1);
                lnkLoginLink.Text = "Logout " + strUserName;
                lnkLoginLink.NavigateUrl = LogoutUrl + "?CURRENTGUID=" + 
strCurrentGuid + "&MSWITCH=Y";
            }
            lnkLoginLink.BreakAfter = false;
            pnlLogin.BreakAfter = true;
            pnlLogin.Controls.Add(lnkLoginLink);
            Controls.Add(pnlLogin);
        }
        
    }
} 

Visual Basic.NET

Imports System
Imports System.Web.UI
Imports System.ComponentModel
Imports System.Web.Mobile
Imports System.Web.UI.MobileControls
Imports Microsoft.ContentManagement.Publishing

' Render a link on a Mobile Web Form to enter
' content editing mode.

<DefaultProperty("LoginUrl"), ToolboxData("<0:MobileLoginLogout _
runat=server></0:MobileLoginLogout>")> _
Public Class MobileLoginLogout
   Inherits MobileUserControl

   Dim _text As String

   <Bindable(True), Category("Appearance"), DefaultValue("")> _
   Property [LinkText]() As String
      Get
         Return _text
      End Get

      Set(ByVal Value As String)
         _text = Value
      End Set
   End Property

   Public LogoutUrl As String
   Public LoginUrl As String

   Protected cxhCms As CmsHttpContext
   Protected poCurrent As Posting
   Protected chCurrent As Channel
   Protected strPostingGuid As String
   Protected strTemplateFile As String

   Protected Overrides Sub CreateChildControls()
      Dim lnkLoginLink As New Link()
      Dim pnlLogin As New Panel()
      Dim strCurrentGuid As String
      Dim sQueryString As String
      Dim strClientUserName As String
      Dim strUserName As String

      ' Call base class
      MyBase.CreateChildControls()

      ' Get the MCMS Http context
      cxhCms = CmsHttpContext.Current

      ' Check if POSTINGGUID is specified.  If
      ' so, we've been template-switched.
      strPostingGuid = Page.Request.QueryString("POSTINGGUID")
      If Not strPostingGuid Is Nothing Then
         poCurrent = cxhCms.Searches.GetByGuid(strPostingGuid)
         chCurrent = poCurrent.Parent
      Else
         poCurrent = cxhCms.Posting
         chCurrent = cxhCms.Channel
      End If

      strCurrentGuid = poCurrent.Guid
      sQueryString = poCurrent.QueryString
      If sQueryString Is Nothing Then
         sQueryString = "CURRENTGUID=" + strCurrentGuid + "&MSWITCH=Y"
      Else
         sQueryString = sQueryString + "&CURRENTGUID=" + strCurrentGuid
      End If
      If (cxhCms.IsLoggedInAsGuest) Then
         lnkLoginLink.Text = "Login"
         lnkLoginLink.NavigateUrl = LoginUrl + "?CURRENTGUID=" + strCurrentGuid
      Else
         strClientUserName = cxhCms.User.ClientAccountName
         strUserName = _
strClientUserName.Substring(strClientUserName.LastIndexOf("/") + 1)
         lnkLoginLink.Text = "Logout " + strUserName
         lnkLoginLink.NavigateUrl = LogoutUrl + "?CURRENTGUID=" + _
         strCurrentGuid + "&MSWITCH=Y"
      End If
      lnkLoginLink.BreakAfter = False
      pnlLogin.BreakAfter = True
      pnlLogin.Controls.Add(lnkLoginLink)
      Controls.Add(pnlLogin)
   End Sub
End Class

The Edit Link Control

The MobileEditLink control will be used to render an Edit link to an authorized user on the Mobile Web Form. It will be used in the later section on "Adding Content Update Capability".

In addition to the "MSWITCH=Y" query string parameter (which ensures a switch to the Mobile Web Form), this control also appends the parameter "MEDIT=Y" to signal to the Mobile Web Form that it should render in content editing mode (more about this in the section "Adding Content Update Capability").

  1. In the Local Project Items category, select the Web Custom Control template. (Don't press Enter or click Open yet.)
  2. In the Name box, type MobileLoginLogout. Click Open.
  3. Select all code in this window (Ctrl—A) and press the Delete key.
  4. Enter the following code into the MobileEditLink code edit view:

Visual C#

using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web.Mobile;
using System.Web.UI.MobileControls;
using Microsoft.ContentManagement.Publishing;

namespace MobileNavControls
{
    /// <summary>
    /// Render a link on a Mobile Web Form to enter
    /// content editing mode.
    /// </summary>
    [ToolboxData("<{0}:MobileEditLink 
runat=server></{0}:MobileEditLink>")]
    public class MobileEditLink : MobileControl
    {
        private string text;
            
        [Bindable(true),
        Category("Appearance"),
        DefaultValue(" . ")]
        public string LinkText
        {
            get
            {
                return text;
            }

            set
            {
                text = value;
            }
        }
        
        protected CmsHttpContext cxhCms;
        protected Posting poCurrent;
        protected Channel chCurrent;
        protected string strPostingGuid;
        protected string strTemplateFile;

        protected override void CreateChildControls()
        {
            //Call base class
            base.CreateChildControls();

            // Get the MCMS Http context
            cxhCms = CmsHttpContext.Current;

            // Check if POSTINGGUID is specified.  If
            // so, we've been template-switched.
            strPostingGuid = base.Page.Request.QueryString["POSTINGGUID"];
            if (strPostingGuid != null)
            {
                poCurrent = (Posting)cxhCms.Searches.GetByGuid(strPostingGuid);
            }
            else
            {
                poCurrent = cxhCms.Posting;
            }
            chCurrent = poCurrent.Parent;

            // Render link only if current user has privileges
            if (!cxhCms.IsLoggedInAsGuest & chCurrent.CanCreatePostings) 
            {
                Link lnkEdit = new Link();
                Panel pnlEdit = new Panel();
            
                // Get the source file name for the mobile template.
                strTemplateFile = poCurrent.Template.SourceFile;

                lnkEdit.BreakAfter = true;
                lnkEdit.NavigateUrl = strTemplateFile + "?POSTINGGUID="
                    + strPostingGuid + "&MSWITCH=Y&MEDIT=Y&"
                    + poCurrent.QueryStringModeUpdate;
                lnkEdit.Text = LinkText;
                lnkEdit.Font.Size = FontSize.Small;
                lnkEdit.Font.Bold = BooleanOption.True;
                pnlEdit.Controls.Add(lnkEdit);
                Controls.Add(pnlEdit);
            }
        }
    }
} 

Visual Basic.NET

Imports System
Imports System.Web.UI
Imports System.ComponentModel
Imports System.Web.Mobile
Imports System.Web.UI.MobileControls
Imports Microsoft.ContentManagement.Publishing

<DefaultProperty("Text"), ToolboxData("<{0}:MobileEditLink _
runat=server></{0}:MobileEditLink>")> _
Public Class MobileEditLink
   Inherits MobileUserControl

   Dim _text As String

   <Bindable(True), Category("Appearance"), DefaultValue(" . ")> _
   Property [LinkText]() As String
      Get
         Return _text
      End Get

      Set(ByVal Value As String)
         _text = Value
      End Set
   End Property

   Protected cxhCms As CmsHttpContext
   Protected poCurrent As Posting
   Protected chCurrent As Channel
   Protected strPostingGuid As String
   Protected strTemplateFile As String

   Protected Overrides Sub CreateChildControls()
      'Call base class
      MyBase.CreateChildControls()

      ' Get the MCMS Http context
      cxhCms = CmsHttpContext.Current

      ' Check if POSTINGGUID is specified.  If
      ' so, we've been template-switched.
      strPostingGuid = Page.Request.QueryString("POSTINGGUID")
      If strPostingGuid <> "" Then
         poCurrent = cxhCms.Searches.GetByGuid(strPostingGuid)
      Else
         poCurrent = cxhCms.Posting
      End If
      chCurrent = poCurrent.Parent

      ' Render link only if current user has privileges
      If Not (cxhCms.IsLoggedInAsGuest) And chCurrent.CanCreatePostings Then
         Dim lnkEdit As New Link()
         Dim pnlEdit As New Panel()

         ' Get the source file name for the mobile template.
         strTemplateFile = poCurrent.Template.SourceFile

         lnkEdit.BreakAfter = True
         lnkEdit.NavigateUrl = strTemplateFile + "?POSTINGGUID=" _
            + strPostingGuid + "&MSWITCH=Y&MEDIT=Y&" _
            + poCurrent.QueryStringModeUpdate
         lnkEdit.Text = LinkText
         lnkEdit.Font.Size = FontSize.Small
         lnkEdit.Font.Bold = BooleanOption.True
         pnlEdit.Controls.Add(lnkEdit)
         Controls.Add(pnlEdit)
      End If
   End Sub
End Class

The Mobile Template Switching Control

The MobileTemplateSwitch control can be embedded into a standard MCMS template that will accomplish a switch from the default template used to publish content to a Mobile Web Form view.

This control assumes that in order to switch to a mobile template, there must be a connected template with the same name as the current template, suffixed by a pre—defined string of characters. The control in this example is implemented with a property (accessible via the Properties window in the IDE) called MobileTemplateIdentifier. In the example in this document, this value is set to " (Mobile)" (note the leading space). For example, if the current template was named "Press Release" then the mobile template would be named "Press Release (Mobile)".

The switch is done whenever the MMIT recognizes that the template is being accessed by a supported mobile device, or a query string parameter of "MSWITCH=Y" is present in the current URL. You can use this latter feature to test the switching from your desktop browser, by appending the query string to the URL in your address bar.

From the Visual Studio .NET IDE, perform the following steps:

  1. In the Local Project Items category, select the Web Custom Control template. (Don't press Enter or click Open yet.)
  2. In the Name box, type MobileTemplateSwitch. Click Open.
  3. Select all code in this window (Ctrl—A) and press the Delete key.
  4. Enter the following code into the MobileTemplateSwitch code edit view:

Visual C#

using System;
using System.Web;
using System.Web.UI;
using System.ComponentModel;
using System.Web.Mobile;
using Microsoft.ContentManagement.Publishing;

namespace MobileNavControls
{
    /// <summary>
    /// Control to detect and cause a switch to a 
    /// mobile template.
    /// </summary>
    [DefaultProperty("Text"), 
        ToolboxData("<{0}:MobileTemplateSwitch runat=server></{0}:MobileTemplateSwitch>")]
    public class MobileTemplateSwitch : System.Web.UI.WebControls.WebControl
    {
        private string text;
    
        [Bindable(true), 
            Category("Appearance"), 
            DefaultValue(" (Mobile)")] 
        public string MobileTemplateIdentifier 
        {
            get
            {
                return text;
            }

            set
            {
                text = value;
            }
        }

        /// <summary> 
        /// Override of Render method to execute template
        /// switch.
        /// </summary>
        /// <param name="output"> The HTML writer to write out to </param>
        protected override void Render(HtmlTextWriter output)
        {
            // Variable declarations.
            Posting poCurrent;
            Template tmCurrent;
            Template tmMobile;
            string strAlternateUrl;
            bool blnSwitch = false;

            // If "MSWITCH=Y" query string parameter is used then switch.
            string strSwitch = base.Page.Request.QueryString["MSWITCH"];
            string strMEdit = base.Page.Request.QueryString["MEDIT"];
            if (strSwitch != null)
            {
                if (strSwitch.ToUpper() == "Y")
                {
                    blnSwitch = true;
                }

                // If "MEDIT=Y" query string parameter is used,
                // we'll pass this through to the alternate template. 
                if (strMEdit != null)
                {
                    if (strMEdit.ToUpper() == "Y")
                    {
                        strMEdit = "&MEDIT=Y";
                    }
                }
            }

            // Instantiate current MCMS context.
            CmsHttpContext cxhCms = CmsHttpContext.Current;

            if (blnSwitch | (base.Page.Request.Browser["IsMobileDevice"] == "true"))
            {
                poCurrent = cxhCms.Posting;
                tmCurrent = poCurrent.Template;

                // Get connected template collection.
                TemplateCollection tcAlternates = tmCurrent.ConnectedTemplates;

                // Select the mobile template from the collection.
                tmMobile = tcAlternates[tmCurrent.Name + MobileTemplateIdentifier];

                // If the mobile template was found, then switch to it.
                if (tmMobile != null)
                {
                    strAlternateUrl = tmMobile.SourceFile + "?POSTINGGUID="
                        + poCurrent.Guid + strMEdit
                        + "&" + poCurrent.QueryStringModeUpdate;
                    System.IO.StringWriter swrTarget = 
                    new System.IO.StringWriter();
                    // If MEDIT=Y is specified, redirect to the alternate
                    // URL.
                    if (strMEdit == "&MEDIT=Y")
                    {
                        base.Page.Response.Redirect (strAlternateUrl);
                    }
                    else
                    {
                        // Execute the alternate URL.
                        base.Page.Server.Execute(strAlternateUrl, swrTarget);
                        // Write the output back to the client.
                        base.Page.Response.Write(swrTarget.ToString());
                        // End the HTTP response.
                        base.Page.Response.End();
                    }
                }
            }
        }
    }
} 

Visual Basic.NET

Imports System
Imports System.Web
Imports System.Web.UI
Imports System.ComponentModel
Imports System.Web.Mobile
Imports Microsoft.ContentManagement.Publishing

<DefaultProperty("Text"), ToolboxData("<{0}:MobileTemplateSwitch _
runat=server></{0}:MobileTemplateSwitch>")> _
Public Class MobileTemplateSwitch
   Inherits System.Web.UI.WebControls.WebControl

   Dim _text As String

   <Bindable(True), Category("Appearance"), DefaultValue(" (Mobile)")> _
   Property MobileTemplateIdentifier() As String
      Get
         Return _text
      End Get

      Set(ByVal Value As String)
         _text = Value
      End Set
   End Property

   ' Override of Render method to execute template
   ' switch.

   Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
      ' Variable declarations.
      Dim poCurrent As Posting
      Dim tmCurrent As Template
      Dim tmMobile As Template
      Dim strAlternateUrl As String
      Dim blnSwitch As Boolean = False

      ' If "MSWITCH=Y" query string parameter is used then switch.
      Dim strSwitch As String = Page.Request.QueryString("MSWITCH")
      Dim strMEdit As String = Page.Request.QueryString("MEDIT")
      If strSwitch <> "" Then
         If strSwitch.ToUpper() = "Y" Then
            blnSwitch = True

            ' If "MEDIT=Y" query string parameter is used,
            ' we'll pass this through to the alternate template. 
            If strMEdit <> "" Then
               If strMEdit.ToUpper() = "Y" Then
                  strMEdit = "&MEDIT=Y"
               End If
            End If
         End If
      End If

      ' Instantiate current MCMS context.
      Dim cxhCms As CmsHttpContext = CmsHttpContext.Current

      If blnSwitch Or (Page.Request.Browser("IsMobileDevice") = "true") Then
         poCurrent = cxhCms.Posting
         tmCurrent = poCurrent.Template

         ' Get connected template collection.
         Dim tcAlternates As TemplateCollection = tmCurrent.ConnectedTemplates

         ' Select the mobile template from the collection.
         tmMobile = tcAlternates(tmCurrent.Name + MobileTemplateIdentifier)

         ' If the mobile template was found, then switch to it.
         If Not tmMobile Is Nothing Then
            strAlternateUrl = tmMobile.SourceFile + "?POSTINGGUID=" _
               + poCurrent.Guid + strMEdit _
               + "&" + poCurrent.QueryStringModeUpdate
            Dim swrTarget As System.IO.StringWriter = New System.IO.StringWriter()
            ' If MEDIT=Y is specified, redirect to the alternate
            ' URL.
            If strMEdit = "&MEDIT=Y" Then
               Page.Response.Redirect(strAlternateUrl)
            Else
               ' Execute the alternate URL.
               Page.Server.Execute(strAlternateUrl, swrTarget)
               ' Write the output back to the client.
               Page.Response.Write(swrTarget.ToString())
               ' End the HTTP response.
               Page.Response.End()
            End If
         End If
      End If
   End Sub
End Class

Build the MobileNavControls

  1. Finally, Build the MobileNavControls solution.
  2. Take note of the output location of the MobilenavControls.dll file. (The default location for this file in a new project will be \My Documents\Visual Studio Projects\MobileNavControls\bin\Debug.) You will need to add a reference to this file in the Mobile Web Forms project that you will create in the next step.
  3. Close the MobileNavControls solution.

Creating the MobileCMS Project

In this step you will build a project that contains the Mobile Web Form version of the Job Posting template.

From the Visual Studio .NET IDE, perform the following steps:

  1. If you still have the MobileNavControls project open, close it now.
  2. From the File menu, select New > Project...
  3. From the New Project Dialog, under Project Types expand the Content Management Server Projects branch and select either Visual Basic Projects or Visual C# Projects, depending on your preference for programming language. (Don't press Enter or click OK yet.)
  4. Under Templates select MCMS Empty Web Project. (Don't press Enter or click OK yet.)
  5. In the Location box change the URL to http://localhost/MobileCMS.
  6. Click OK. Visual Studio will begin the creation of your new project.
  7. A message will pop up indicating that in order to MCMS—enable the project, a new web.config file will be created. Click OK.
  8. In the IDE, make sure that you have the following objects visible:
    • Solution Explorer (Ctrl—Alt—L)
    • MCMS Template Explorer (View > Other Windows > MCMS Template Explorer)
  9. In the Solution Explorer, right—click MobileCMS, click Add, and then click New Folder.
  10. Name the new folder Templates.
  11. If your solution was created without a global.asax file:
    1. In the Solution Explorer, right-click MobileCMS and select Add > New Item...
    2. In the Add New Item dialog, under Categories, select Web Project Items. (Don't hit Enter or click Open yet.)
    3. Under Templates, select Global Application Class and click Open. This will create either a global.asax.cs file (for a C# project) or a global.asax.vb file (for a VB project).
    4. Close the design view window for global.asax.
  12. Add a reference to MobileNavControls. When you performed the Build for MobileNavControls, you noted the location of the output .dll file. Right—click the WoodgroveNet project, select Add Reference, and browse to the MobileNavControls.dll file.
  13. Build the MobileCMS project. Note the location of the output .dll file for this project (normally \Inetpub\wwwroot\MobileCMS\bin).

Modifying WoodgroveNet

To save time in this example, you will modify the WoodgroveNet sample site.

If you installed WoodgroveNet from the MCMS 2002 product CD, the site is built using C#. If you wish to work in Visual Basic .NET you must download from http://go.microsoft.com/fwlink/?LinkId=17402 and install the WoodgroveNetVB sample from Microsoft.

This process assumes that you've already installed this sample data, which is included with the MCMS 2002 installation CD. It is further assumed that you have enabled MCMS Guest Access (via the MCMS Server Configuration Application (SCA)).

Please note that the sample data is not a requirement for building Mobile Web Forms with MCMS; it's simply included here to provide a preexisting content environment which can be used for testing the example. If you wish to create your own new MCMS Web Project, you will need to ensure that you have created a functioning MCMS environment (with channels, template galleries and templates for browsing and authoring).

From the Visual Studio .NET IDE (with your MobileCMS solution open) perform the following steps:

  1. In the Solution Explorer, right—click Solution 'MobileCMS ', click Add, and then click Add Existing Project.
  2. Add WoodgroveNet to your MobileCMS solution as follows:
    1. If you're working in C#: In the Add Existing Project dialog, locate the WoodgroveNet.csproj (installed in \Program Files\Microsoft Content Management Server\Sample Data\WoodgroveNet\), select it, and click Open.
    2. If you're working in Visual Basic .NET: In the Add Existing Project dialog, locate the WoodgroveNetVB.vbproj (installed in \Inetpub\wwwroot\WoodgroveNetVB\), select it, and click Open.
  3. Add a reference to MobileCMS: Right-click on the WoodgroveNet (for C# users) or WoodgroveNetVB (for Visual Basic users) project, select Add Reference..., and then click the Projects tab. You should see the MobileCMS.dll file. Click Select and OK.
  4. Add a reference to MobileNavControls. When you performed the Build for MobileNavControls, you noted the location of the output .dll file. Right—click the WoodgroveNet (for C# users) or WoodgroveNetVB (for Visual Basic users) project, select Add Reference..., and browse to the MobileNavControls.dll file.
  5. From the IDE menu, launch the MCMS Site Manager by selecting Tools > Content Management Server > Site Manager. Log in as the Administrator.
  6. Under User Roles, select Subscribers, and then double—click the CMS Guest group.
  7. Select the Group Members tab, and ensure that your MCMS Guest Access Account (that you set up during MCMS install and configuration) is added to this group. If you have not done this yet, create the account, enable Guest Access via the SCA, and add it to this rights group.
  8. Ensure that the CMS Guest subscriber rights group has access to all WoodgroveNet (for C# users) or WoodgroveNetVB (for Visual Basic users) containers.
  9. Close the MCMS Site Manager.

WoodgroveNet (or WoodgroveNetVB) is now added to your solution, ready for extension to support mobile devices.

Modifying the JobPosting Template

In this example, the Job Posting template will be modified to include the MobileTemplateSwitching control. You will also enable session state for the template.

From the Visual Studio .NET IDE, perform the following steps:

  1. In the Solution Explorer, within the WoodgroveNet (C#) or WoodgroveNetVB (Visual Basic) project, expand the Templates folder and double—click the JobPosting template.
  2. Switch to HTML view, and add the following Register directive to the top of the template:
    <%@ Register TagPrefix="custom" Namespace="MobileNavControls" 
    Assembly="MobileNavControls" %>
    
  3. Immediately prior to the <HTML> tag, add the following instance of the control:
    <custom:MobileTemplateSwitch MobileTemplateIdentifier=" (Mobile)" 
    id="MobileTemplateSwitch1" 
    runat="server"></custom:MobileTemplateSwitch>
    

    Note that it is important that this control reference occurs before the HTML tag, as this will prevent the tag from being rendered on a non—HTML mobile device before the appropriate WML is rendered by our template switching method. Switching back to design view in the IDE will reposition the control to a location inside the <HTML></HTML> block. If this occurs, switch back to HTML view and move the control above the <html> tag.

  4. Enable Session State for the template. In the Properties window, the enableSessionState property for the DOCUMENT will be set to False. Set it to True. (This will insert "EnableSessionState="True"" into the Page directive at the top of the template HTML view.)
  5. Save the template and close the editor window.
  6. Rebuild the WoodgroveNet (C#) or WoodgroveNetVB (Visual Basic) solution.

The Job Posting template is now ready for switching. Until the mobile template is available (which you will prepare in the next section), the template will not perform a redirect and the original template will be rendered.

Creating a Mobile Template

In this section you will create a Mobile Web Form, register it in the MCMS template gallery, and connect it to the Template Gallery Item (TGI) named Job Posting ASPX (for use with the C# version of WoodgroveNet) or Job Posting ASPX VB (for use with the Visual Basic version). The Job Posting template has four placeholders that you will access through the Mobile Web Form using the MCMS Publishing API.

From the Visual Studio .NET IDE, perform the following steps:

  1. In the Solution Explorer, within the MobileCMS project, right—click Templates, click Add, and then click Add New Item.
  2. From the Add New Items dialog, in the Categories pane, confirm that the Web Project Items branch is selected.
  3. Under Templates, select Mobile Web Web Form. (Don't press Enter or click Open yet.)
  4. In the Name box, type JobPostingMobile. Click Open.
  5. Switch to HTML view, and add the following Register directive to the top of the template:
    <%@ Register TagPrefix="custom" Namespace="MobileNavControls" Assembly="MobileNavControls" %>
    
  6. Select all text between the <body> and </body> tags and Delete it.
  7. Enter the following text in between the <body> and </body> tags:
        <mobile:form id="frmDisplay" runat="server">
            <custom:MobileBreadcrumb id="Mobilebreadcrumb1" 
            runat="server" SeparatorText=" - ">
            </custom:MobileBreadcrumb>
            <mobile:TextView id="txvTitle" runat="server" Font-Bold="True">
            txvTitle</mobile:TextView>
            <mobile:Label id="lblJobDescription" runat="server" Font-Bold="True">
            Job Description</mobile:Label>
            <mobile:TextView id="txvJobDescription" runat="server">
            txvJobDescription</mobile:TextView>
            <mobile:Label id="lblQualifications" runat="server" Font-Bold="True">
            Qualifications</mobile:Label>
            <mobile:TextView id="txvQualifications" runat="server">
            txvQualifications</mobile:TextView>
            <mobile:Label id="lblApplicationInstructions" 
            runat="server" Font-Bold="True">
            Application Instructions</mobile:Label>
            <mobile:TextView id="txvApplicationInstructions" runat="server">
            txvApplicationInstructions</mobile:TextView>
            <custom:MobileNavList id="MobileNavList1" 
            runat="server" SeparatorText=" - ">
            </custom:MobileNavList>
        </mobile:form>
    
  8. Switch to Design view. The form should have the following controls and properties as in the following table:

    Table 2.

    Control ID Bold Text
    TextView txvTitle True txvTitle
    Label lblJobDescription True Job Description
    TextView txvJobDescription False txvJobDescription
    Label lblQualifications True Qualifications
    TextView txvQualifications False txvQualifications
    Label lblApplicationInstructions True Application Instructions
    TextView txvApplicationInstructions False txvApplicationInstructions

    In the IDE your form layout should look as it does in the following figure:

    Figure 2. Form layout in the IDE

  9. Save the form.
  10. Right—click the body of the form, and then select View Code.

    Visual C#

    Following the last using directive, add:

    using Microsoft.ContentManagement.Publishing;
    using Microsoft.ContentManagement.Publishing.Extensions.Placeholders;
    

Visual Basic.NET

Before the Public Class statement, add:

Imports Microsoft.ContentManagement.Publishing
Imports Microsoft.ContentManagement.Publishing.Extensions.Placeholders
  1. Add member variable declarations:

    Visual C#

    Before the statement:

    private void Page_Load(object sender, System.EventArgs e)
    

    Add the following statements:

    protected CmsHttpContext cxhCms;
    protected Posting poCurrent;
    protected Channel chCurrent;
    protected HtmlPlaceholder phTitle;
    protected HtmlPlaceholder phJobDescription;
    protected HtmlPlaceholder phQualifications;
    protected HtmlPlaceholder phApplicationInstructions;
    protected string strPostingGuid;
    

Visual Basic.NET

Before the statement:

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Add the following statements:

Protected cxhCms As CmsHttpContext
Protected poCurrent As Posting
Protected chCurrent As Channel
Protected phTitle As HtmlPlaceholder
Protected phJobDescription As HtmlPlaceholder
Protected phQualifications As HtmlPlaceholder
Protected phApplicationInstructions As HtmlPlaceholder
Protected strPostingGuid As String
  1. Inside the Page_Load method, insert the following code:

    Visual C#

    // Get the MCMS Http context
    cxhCms = CmsHttpContext.Current;
    
    // Check if POSTINGGUID is specified. If
    // so, we've been template-switched.
    strPostingGuid = base.Page.Request.QueryString["POSTINGGUID"];
    if (strPostingGuid != null)
    {
        poCurrent = (Posting)cxhCms.Searches.GetByGuid(strPostingGuid);
        chCurrent = poCurrent.Parent;
    }
    else
    {
        poCurrent = cxhCms.Posting;
        chCurrent = cxhCms.Channel;
    }
    
    // Get Placeholders
    phTitle = (HtmlPlaceholder)poCurrent.Placeholders["Title"];
    phJobDescription = (HtmlPlaceholder)poCurrent.Placeholders["JobDescription"];
    phQualifications = (HtmlPlaceholder)poCurrent.Placeholders["Qualifications"];
    phApplicationInstructions = 
    (HtmlPlaceholder)poCurrent.Placeholders["ApplicationInstructions"];
    
    // Initially populate the Web Form controls
    if (!IsPostBack)
    {
        PopulateControls();
    }
    

Visual Basic.NET

' Get the MCMS Http context
cxhCms = CmsHttpContext.Current

' Check if POSTINGGUID is specified.  If
' so, we've been template-switched.
strPostingGuid = Page.Request.QueryString("POSTINGGUID")
If strPostingGuid <> "" Then
     poCurrent = cxhCms.Searches.GetByGuid(strPostingGuid)
     chCurrent = poCurrent.Parent
Else
     poCurrent = cxhCms.Posting
     chCurrent = cxhCms.Channel
End If

' Get Placeholders
phTitle = poCurrent.Placeholders("Title")
phJobDescription = poCurrent.Placeholders("JobDescription")
phQualifications = poCurrent.Placeholders("Qualifications")
phApplicationInstructions = poCurrent.Placeholders("ApplicationInstructions")

' Initially populate the Web Form controls
If Not IsPostBack Then
     PopulateControls()
End If
  1. Following the Page_Load method, insert the PopulateControls method:

    Visual C#

    /// <summary>
    /// Populate Mobile Web Form Controls
    /// with Placeholder Content
    /// </summary>
    private void PopulateControls()
    {
        // Always check if the placeholder object exists
        if (phTitle != null)
        {
            txvTitle.Text = phTitle.Text;
        }
        if (phJobDescription != null)
        {
            txvJobDescription.Text = phJobDescription.Text;
        }
        if (phQualifications != null)
        {
            txvQualifications.Text = phQualifications.Text;
        }
        if (phApplicationInstructions != null)
        {
            txvApplicationInstructions.Text = phApplicationInstructions.Text;
        }
    }
    

    Visual Basic.NET

    ' Populate Mobile Web Form Controls
    ' with Placeholder Content
    Private Sub PopulateControls()
        ' Always check if the placeholder object exists
        If Not phTitle Is Nothing Then
             txvTitle.Text = phTitle.Text
        End If
        If Not phJobDescription Is Nothing Then
             txvJobDescription.Text = phJobDescription.Text
        End If
        If Not phQualifications Is Nothing Then
             txvQualifications.Text = phQualifications.Text
        End If
        If Not phApplicationInstructions Is Nothing Then
             txvApplicationInstructions.Text = phApplicationInstructions.Text
        End If
    End Sub
    
  2. Save the file.
  3. From the MCMS Template Explorer window (if it's not visible, select View > Other Windows > MCMS Template Explorer), locate the Job Posting ASPX (for C#) or Job Posting ASPX VB (for Visual Basic) template under Templates > WoodgroveNet (or WoodgroveNetVB) > About Us Net.
  4. Right—click Job Posting ASPX (for C#) or Job Posting ASPX VB (for Visual Basic) and then click Create Connected.
  5. A pop—up displays a message warning about locking this template from check out by other users. Click Yes.
  6. Rename the New Template to Job Posting ASPX (Mobile) (C#) or Job Posting ASPX VB (Mobile) (Visual Basic).
  7. Modify the properties for the new template: change the value to /MobileCMS/Templates/JobPostingMobile.aspx, or click the ellipsis button ("...") in the value box for the TemplateFile property and browse to this file.
  8. In the Template Explorer window, right—click Job Posting ASPX (Mobile) (C#) or Job Posting ASPX VB (Mobile) (Visual Basic) and then click Check In.

    Your Template Explorer window should appear as it does in the following figure (the C# version is shown...the Visual Basic version will look similar):

    Figure 3. Template Explorer window

  9. Build the MobileCMS project.
  10. Rebuild the WoodgroveNet (for C# users) or WoodgroveNetVB (for Visual Basic users) project.
  11. Browse to a Job Posting page, such as http://localhost/WoodgroveNet/About+Us/Careers/IT+Assistant.htm. (C#), or http://localhost/WoodgroveNetVB/About+Us/Careers/IT+Assistant.htm (Visual Basic).
  12. In the address bar of your browser, append the characters ?MSWITCH=Y to the URL and press ENTER. You should now see the mobile device view.

    If you have a connected mobile device that can access your site, browse to the same URL (without the ?MSWITCH=Y parameter). The following figure shows how this appears (as an HTML page) in Internet Explorer running on Pocket PC 2002:

    Figure 4. Page view in Internet Explorer with Pocket PC

The previous figure shows the Mobile Web Form rendered by an HTML browser. If this form is viewed by a WML browser, the view will be virtually identical. The following figure shows the same form rendered on a WAP device emulator, supporting WML 1.1:

Figure 5. Page view on a WAP device emulator

(Note that the ability of IIS to recognize your device is dependent on the level of device support enabled in your current MMIT configuration. You may extend this by adding new device adapters or make changes to the web.config file for your project. Consult the section on "Adding New Device Adapters and Device Support" in the online documentation for the MMIT for more details.)

The WML is generated automatically for this device by the MMIT. The generated WML for this page is as follows (the source shown is for the WoodgroveNet C# version; the WoodgroveNetVB version will look similar):

<?xml version='1.0'?>
<!DOCTYPE wml PUBLIC '-//WAPFORUM//DTD WML 1.1//EN' 
'http://www.wapforum.org/DTD/wml_1.1.xml'><wml><head>
<meta http-equiv="Cache-Control" content="max-age=0" />
</head>
<card>
<do type="prev" label="Back"><prev /></do>
<p><b><a href="/Channels/?MSWITCH=Y" title="Home">Home</a> - 
<a href="/WoodgroveNet/?MSWITCH=Y" title="Link">WoodgroveNet</a> - 
<a href="/WoodgroveNet/About+Us/?MSWITCH=Y" title="Link">About Us</a> - 
<a href="/WoodgroveNet/About+Us/Careers/?MSWITCH=Y" title="Link">Careers</a><br/>
Information Technology Assistant 7</b><br/>
<b>Job Description</b><br/>
You will help the Manager and Director of IT configure hardware and software 
for the rest of the organization.<br/>
<b>Qualifications</b><br/>
You are familiar with Microsoft operating systems. You have an understanding of 
networking and security. A technical degree or diploma is required.<br/>
<b>Application Instructions</b><br/>
Send your resume and a copy of your transcripts to it@woodgrovebank.com. Phone 
calls will not be accepted.<br/>
<small><a href="/WoodgroveNet/About+Us/Careers/Help+Desk+Analyst.htm?MSWITCH=Y" 
title="Link">Help Desk Analyst</a></small> - 
<small><a href="/WoodgroveNet/About+Us/Careers/Account+Manager.htm?MSWITCH=Y" 
title="Link">Account Manager</a></small></p></card>
</wml>

Adding Content Update Capability

In this section you will add the ability of an authorized user to update content from a mobile device. This will require the addition of:

  • A login dialog
  • An edit link on the Mobile Web Form
  • An additional edit—mode form element to allow the modification of content
  • Submit and Cancel buttons

To simplify the example, the authentication form will not employ the use of SSL. In a production environment it is strongly recommended that you employ maximum security features to ensure the protection of authentication credentials and content resources.

As well in the example, submitted content will be automatically approved if the user has that authority.

As discussed earlier in this document, this example will not attempt to enable the full range of content management functions, but rather serve as a simple example of how to implement some of these capabilities in a limited range. This can serve as a starting point to implement more comprehensive capabilities if required.

A Mobile Authentication Form

In order to perform content editing, an author must first be allowed to log in to the MCMS site. In this step you will create two Mobile Web Forms required to accomplish this:

  • MobileLogin: The user name/password entry form.
  • MobileLogout: A simple form to log out the current user.

From the Visual Studio .NET IDE, perform the following steps:

  1. In the Solution Explorer, within the MobileCMS project, right—click Templates, click Add, and then click Add New Item.
  2. In the Templates panel select Mobile Web Form (don't press Enter or click Open yet).
  3. In the Name box type MobileLogin, and then click Open.
  4. Switch to HTML view mode.
  5. Delete the line containing the "<mobile:Form>" tag.
  6. Enter the following code between the <body> and </body> tags:
    <mobile:Form id="frmLogin" runat="server">
        <mobile:Label id="lblDomain" runat="server">Domain:</mobile:Label>
        <mobile:SelectionList id="selDomain" runat="server"></mobile:SelectionList>
        <mobile:Label id="lblUserName" runat="server">User Name:</mobile:Label>
        <mobile:TextBox id="txtUserName" runat="server"></mobile:TextBox>
        <mobile:Label id="lblPassword" runat="server">Password:</mobile:Label>
        <mobile:TextBox id="txtPassword" runat="server" Password="True">
        </mobile:TextBox>
        <mobile:Command id="btnLogin" runat="server">Login</mobile:Command>
        <mobile:Label id="lblLoginMessage" runat="server" Visible="False">
        </mobile:Label>
    </mobile:Form>
    
  7. Switch back to Design view. Your form should appear as in the following figure:

    Figure 6. Form in Design view

  8. Right—click the form and then select View Code.
  9. Add namespace references.

    Visual C#

    Following the last using directive, add:

    using Microsoft.ContentManagement.Web.Security;
    using Microsoft.ContentManagement.Publishing;
    using System.Collections.Specialized;
    

    Visual Basic.NET

    Before the Public Class statement, add:

    Imports Microsoft.ContentManagement.Web.Security
    Imports Microsoft.ContentManagement.Publishing
    Imports System.Collections.Specialized
    
  10. Immediately before the Page_Load method, enter the following code:

    Visual C#

    protected string strNTDomain = "";
    protected string strNextUrl = "";
    protected string strGuid = "";
    

    Visual Basic.NET

    Protected strNTDomain As String = ""
    Protected strNextUrl As String = ""
    Protected strGuid As String = ""
    
  11. Inside the Page_Load method, enter the following code:

    Visual C#

    // Get the list of domains
    StringCollection stcDomains = CmsFormsAuthentication.Domains;
    
    foreach ( string strDomain in stcDomains )
    {
        string strDomainWinNT = strDomain.Substring( 0, 8 );
        string strDomainAdd = strDomain;
        // Check to see if WinNT domain.
        if ( strDomainWinNT.ToUpper() == "WINNT://")
        {
            // Set the displayed value of each option
            // to the domain name w/o the "WinNT://" in front.
            strDomainAdd = strDomain.Substring( 8 );
        }
        // For LDAP (and all other) entries, just use the
        // literal name for the display name
        selDomain.Items.Add(strDomainAdd);
    }
    
    // if only one domain, don't display the selection list.
    if (selDomain.Items.Count == 1)
    {
        strNTDomain = selDomain.Items[0].Value;
        selDomain.SelectedIndex = 0;
        selDomain.Visible = false;
        lblDomain.Visible = false;
    }
    

    Visual Basic.NET

    ' Get the list of domains
    Dim stcDomains As StringCollection = CmsFormsAuthentication.Domains
    Dim strDomain As String
    Dim strDomainWinNT As String
    Dim strDomainAdd As String
    
    For Each strDomain In stcDomains
         strDomainWinNT = strDomain.Substring(0, 8)
         strDomainAdd = strDomain
         ' Check to see if WinNT domain.
         If strDomainWinNT.ToUpper() = "WINNT://" Then
                ' Set the displayed value of each option
                ' to the domain name without the "WinNT://" in front.
                strDomainAdd = strDomain.Substring(8)
         End If
         ' For LDAP (and all other) entries, just use the
         ' literal name for the display name
         selDomain.Items.Add(strDomainAdd)
    Next
    
    ' if only one domain, don't display the selection list.
    If selDomain.Items.Count = 1 Then
         strNTDomain = selDomain.Items(0).Value
         selDomain.SelectedIndex = 0
         selDomain.Visible = False
         lblDomain.Visible = False
    End If
    
  12. Return to the MobileLogin.aspx Web form and double—click the Login button.
  13. Enter the following code into the btnLogin_Click method:

    Visual C#

    // Login and redirect back to page.
    strNTDomain = selDomain.Items[selDomain.SelectedIndex].Value;
    string strNTUser = txtUserName.Text;
    string strNTPassword = txtPassword.Text;
    
    strNTDomain = strNTDomain.Trim();
    
    try
    {
        if(strNTUser.IndexOf( "@" ) == -1)
        {
            strNTUser = "WinNT://" + strNTDomain + "/" + strNTUser;
        }
    }
    catch(ArgumentOutOfRangeException)
    {
        lblLoginMessage.Text = "Argument out of range.";
    }
    try
    {
        CmsHttpContext cxhCms = CmsHttpContext.Current;
        CmsAuthenticationTicket ticket = 
    CmsFormsAuthentication.AuthenticateAsUser(strNTUser, strNTPassword, 
    strNTUser, "FirstName");
    
        if( ticket != null )
        {
            strGuid = Request.QueryString["CURRENTGUID"];
            if (strGuid != null)
            {
                CmsFormsAuthentication.SetAuthCookie(ticket, true, false);
                Posting poCurrent = (Posting)cxhCms.Searches.GetByGuid(strGuid);
                strNextUrl = poCurrent.UrlModePublished + "?MSWITCH=Y";
                RedirectToMobilePage (strNextUrl);
            }
            else
            {
                RedirectToMobilePage ("/Channels/");
            }
    
        }
    
        // If it got here, it means the redirect didn't occur
        // so the username/password is not valid.
        lblLoginMessage.Visible = true;
        lblLoginMessage.Text = "Invalid user name or password entered.";
    }
    
        // Catching the Exceptions thrown
    catch(Exception)
    {
        lblLoginMessage.Text = "A General Exception occurred.";
    }
    

    Visual Basic.NET

    Dim strNTUser As String
    Dim strNTPassword As String
    Dim cxhCms As CmsHttpContext
    Dim ticket As CmsAuthenticationTicket
    Dim poCurrent As Posting
    Dim strNextUrl As String
    
    ' Login and redirect back to page.
    strNTDomain = selDomain.Items(selDomain.SelectedIndex).Value
    strNTUser = txtUserName.Text
    strNTPassword = txtPassword.Text
    strNTDomain = strNTDomain.Trim()
    
    Try
         If strNTUser.IndexOf("@") = -1 Then
                strNTUser = "WinNT://" + strNTDomain + "/" + strNTUser
         End If
    Catch ArgumentOutOfRangeException As Exception
         lblLoginMessage.Text = "Argument out of range."
    End Try
    
    Try
         cxhCms = CmsHttpContext.Current
         ticket = CmsFormsAuthentication.AuthenticateAsUser(strNTUser, 
         strNTPassword, strNTUser, "FirstName")
         If Not ticket Is Nothing Then
                strGuid = Request.QueryString("CURRENTGUID")
                If Not strGuid Is Nothing Then
                     CmsFormsAuthentication.SetAuthCookie(ticket, True, False)
                     poCurrent = cxhCms.Searches.GetByGuid(strGuid)
                     strNextUrl = poCurrent.UrlModePublished + "?MSWITCH=Y"
                     RedirectToMobilePage(strNextUrl)
                Else
                     RedirectToMobilePage("/Channels/")
                End If
         End If
    
         ' If it got here, it means the redirect didn't occur
         ' so the username/password is not valid.
         lblLoginMessage.Visible = True
         lblLoginMessage.Text = "Invalid user name or password entered."
    
    Catch ex As Exception
         ' Catching the Exceptions thrown
         lblLoginMessage.Text = "A General Exception occurred."
    End Try
    
  14. Build the MobileCMS project to check for any compile errors.
  15. In the Solution Explorer, within the MobileCMS project, right—click Templates, click Add, and then click Add New Item.
  16. In the Templates panel select Mobile Web Form (don't press ENTER or click Open yet).
  17. In the Name box type MobileLogout, and then click Open.
  18. Right—click the form, and then select View Code.
  19. Add namespace references.

    Visual C#

    Following the last using directive, add:

    using Microsoft.ContentManagement.Web.Security;
    using Microsoft.ContentManagement.Publishing;
    

    Visual Basic.NET

    Imports Microsoft.ContentManagement.Web.Security
    Imports Microsoft.ContentManagement.Publishing
    
  20. Immediately before the Page_Load method, enter the following code:

    Visual C#

    protected string strGuid;
    protected string strNextUrl;
    

    Visual Basic.NET

    Protected strGuid As String
    Protected strNextUrl As String
    
  21. Inside the Page_Load method, enter the following code:

    Visual C#

    // Get the MCMS HTTP Context.
    CmsHttpContext cxhCms = CmsHttpContext.Current;
    // Sign out.
    CmsFormsAuthentication.SignOut();
    // Establish publish mode URL to return.
    strGuid = Request.QueryString["CURRENTGUID"];
    if (strGuid != null)
    {
        Posting poCurrent = (Posting)cxhCms.Searches.GetByGuid(strGuid);
        strNextUrl = poCurrent.UrlModePublished + "?MSWITCH=Y";
    }
    else
    {
        strNextUrl = "/Channels/";
    }
    RedirectToMobilePage(strNextUrl, true);
    

    Visual Basic.NET

    Dim cxhCms As CmsHttpContext
    Dim poCurrent As Posting
    
    ' Get the MCMS HTTP Context.
    cxhCms = CmsHttpContext.Current
    ' Sign out.
    CmsFormsAuthentication.SignOut()
    ' Establish publish mode URL to return.
    strGuid = Request.QueryString("CURRENTGUID")
    If Not strGuid Is Nothing Then
         poCurrent = cxhCms.Searches.GetByGuid(strGuid)
         strNextUrl = poCurrent.UrlModePublished + "?MSWITCH=Y"
    Else
         strNextUrl = "/Channels/"
    End If
    RedirectToMobilePage(strNextUrl, True)
    
  22. Build the MobileCMS project to check for any compile errors.

Adding Controls to the Mobile Template

In this step, you will:

  • Add the login/logout and edit link controls to the Mobile Web Form
  • Add the editing form
  • Extend the Mobile Web Form logic to handle login and content editing.

From the Visual Studio .NET IDE, perform the following steps:

  1. In the Solution Explorer, within the MobileCMS project, double—click the JobPostingMobile template file.
  2. Switch to HTML view.
  3. Immediately before the line containing the "<custom:MobileBreadcrumb" reference, insert the following control references:
    <custom:MobileLoginLogout id="MobileLoginLogout1" runat="server" 
    LoginUrl="/MobileCMS/Templates/MobileLogin.aspx" 
    LogoutUrl="/MobileCMS/Templates/MobileLogout.aspx"></custom:MobileLoginLogout>
    <custom:MobileEditLink id="MobileEditLink1" runat="server" 
    LinkText="Edit"></custom:MobileEditLink>
    
  4. Immediately before the </body> closing tag at the end of the form, insert the following control references:
    <mobile:form id="frmEdit" runat="server">
        <mobile:Label id="lblTitle" runat="server" Font-Bold="True">
        Job Title</mobile:Label>
        <mobile:TextBox id="txbTitle" runat="server" Wrapping="Wrap" Size="40">
        </mobile:TextBox>
        <mobile:Label id="lblDescription2" runat="server" Font-Bold="True">
        Job Description</mobile:Label>
        <mobile:TextBox id="txbJobDescription" runat="server" Wrapping="Wrap" Size="40">
        </mobile:TextBox>
        <mobile:Label id="lblQualifications2" runat="server" Font-Bold="True">
        Qualifications</mobile:Label>
        <mobile:TextBox id="txbQualifications" runat="server" Wrapping="Wrap" Size="40">
        </mobile:TextBox>
        <mobile:Label id="lblApplicationInstructions2" runat="server" Font-Bold="True">
        Application Instructions</mobile:Label>
        <mobile:TextBox id="txbApplicationInstructions" runat="server" 
    Wrapping="Wrap" Size="40"></mobile:TextBox>
        <mobile:Command id="btnSubmit" runat="server" CausesValidation="False">
        Submit</mobile:Command>
        <mobile:Command id="btnCancel" runat="server" 
    CausesValidation="False" CommandName="Cancel">Cancel</mobile:Command>
    </mobile:form>
    
  5. Switch to Design view. Your Web form should appear as in the following figure:

    Figure 7. Form in Design view

  6. Within the frmEdit form, double—click the first TextBox control (txbTitle). This will switch to the code view for the txbTitle_TextChanged method.
  7. Insert the following code into the txbTitle_TextChanged method:

    Visual C#

    phTitle.Html = txbTitle.Text;
    txvTitle.Text = txbTitle.Text;
    

    Visual Basic.NET

    phTitle.Html = txbTitle.Text
    txvTitle.Text = txbTitle.Text
    
  8. Return to the Design view for the JobPostingMobile form.
  9. Within the frmEdit form, double—click the second TextBox control (txbJobDescription). This will switch to the code view for the txbJobDescription_TextChanged method.
  10. Insert the following code into the txbJobDescription _TextChanged method:

    Visual C#

    phJobDescription.Html = txbJobDescription.Text;
    txvJobDescription.Text = txbJobDescription.Text;
    

    Visual Basic.NET

    phJobDescription.Html = txbJobDescription.Text
    txvJobDescription.Text = txbJobDescription.Text
    
  11. Return to the Design view for the JobPostingMobile form.
  12. Within the frmEdit form, double—click the third TextBox control (txbQualifications). This will switch to the code view for the txbQualifications_TextChanged method.
  13. Insert the following code into the txbQualifications_TextChanged method:

    Visual C#

    phQualifications.Html = txbQualifications.Text;
    txvQualifications.Text = txbQualifications.Text;
    

    Visual Basic.NET

    phQualifications.Html = txbQualifications.Text
    txvQualifications.Text = txbQualifications.Text
    
  14. Return to the Design view for the JobPostingMobile form.
  15. Within the frmEdit form, double—click the fourth TextBox control (txbApplicationInstructions). This will switch to the code view for the txbApplicationInstructions_TextChanged method.
  16. Insert the following code into the txbApplicationInstructions_TextChanged method:

    Visual C#

    phApplicationInstructions.Html = txbApplicationInstructions.Text;
    txvApplicationInstructions.Text = txbApplicationInstructions.Text;
    

    Visual Basic.NET

    phApplicationInstructions.Html = txbApplicationInstructions.Text
    txvApplicationInstructions.Text = txbApplicationInstructions.Text
    
  17. Return to the Design view for the JobPostingMobile form.
  18. Within the frmEdit form, double—click the Submit control. This will switch to the code view for the btnSubmit_Click method.
  19. Insert the following code into the btnSubmit_Click method:

    Visual C#

    // Commit the MCMS transaction
    cxhCms.CommitAll();
    // Submit and/or approve content if permitted
    SubmitApprove();
    // Switch back to display view
    ActiveForm = frmDisplay;
    

    Visual Basic.NET

    ' Commit the MCMS transaction
    cxhCms.CommitAll()
    ' Submit and/or approve content if permitted
    SubmitApprove()
    ' Switch back to display view
    ActiveForm = frmDisplay
    
  20. Return to the Design view for the JobPostingMobile form.
  21. Within the frmEdit form, double—click the Cancel control. This will switch to the code view for the btnCancel_Click method.
  22. Insert the following code into the btnCancel_Click method:

    Visual C#

    // Roll back any pending changes
    cxhCms.RollbackAll();
    // Re-populate controls from placeholders
    PopulateControls();
    // Switch back to display view
    ActiveForm = frmDisplay;
    

    Visual Basic.NET

    ' Roll back any pending changes
    cxhCms.RollbackAll()
    ' Re-populate controls from placeholders
    PopulateControls()
    ' Switch back to display view
    ActiveForm = frmDisplay
    
  23. Remaining in the code editor, locate the PopulateControls method. Replace the current method with the following code:

    Visual C#

    /// <summary>
    /// Populate Mobile Web Form Controls
    /// with Placeholder Content
    /// </summary>
    private void PopulateControls()
    {
        // Always check if the placeholder object exists
        if (phTitle != null)
        {
            txvTitle.Text = phTitle.Text;
            txbTitle.Text = phTitle.Text;
        }
        if (phJobDescription != null)
        {
            txvJobDescription.Text = phJobDescription.Text;
            txbJobDescription.Text = phJobDescription.Text;
        }
        if (phQualifications != null)
        {
            txvQualifications.Text = phQualifications.Text;
            txbQualifications.Text = phQualifications.Text;
        }
        if (phApplicationInstructions != null)
        {
            txvApplicationInstructions.Text = phApplicationInstructions.Text;
            txbApplicationInstructions.Text = phApplicationInstructions.Text;
        }
    }
    

    Visual Basic.NET

    ' Populate Mobile Web Form Controls
    ' with Placeholder Content
    Private Sub PopulateControls()
        ' Always check if the placeholder object exists
        If Not phTitle Is Nothing Then
             txvTitle.Text = phTitle.Text
             txbTitle.Text = phTitle.Text
        End If
        If Not phJobDescription Is Nothing Then
             txvJobDescription.Text = phJobDescription.Text
             txbJobDescription.Text = phJobDescription.Text
        End If
        If Not phQualifications Is Nothing Then
             txvQualifications.Text = phQualifications.Text
             txbQualifications.Text = phQualifications.Text
        End If
        If Not phApplicationInstructions Is Nothing Then
             txvApplicationInstructions.Text = phApplicationInstructions.Text
             txbApplicationInstructions.Text = phApplicationInstructions.Text
        End If
    End Sub
    
  24. Following the PopulateControls method, insert the following code:

    Visual C#

    /// <summary>
    /// Submit and/or approve posting if allowed.
    /// </summary>
    private void SubmitApprove()
    {
        if (poCurrent.CanSubmit)
        {
            // Submit the transaction
            poCurrent.Submit();
            // Commit the transaction
            cxhCms.CommitAll();
        }
        if (poCurrent.CanApprove)
        {
            // Submit the transaction
            poCurrent.Approve();
            // Commit the transaction
            cxhCms.CommitAll();
        }
    }
    

    Visual Basic.NET

    ' Submit and/or approve posting if allowed.
    Private Sub SubmitApprove()
        If (poCurrent.CanSubmit) Then
             ' Submit the transaction
             poCurrent.Submit()
             ' Commit the transaction
             cxhCms.CommitAll()
        End If
        If (poCurrent.CanApprove) Then
             ' Submit the transaction
             poCurrent.Approve()
             ' Commit the transaction
             cxhCms.CommitAll()
        End If
    End Sub
    
  25. At the end of the Page_Load method add the following code to switch to edit mode if the MEDIT=Y query string parameter is present:

    Visual C#

    // Switch to edit form if MEDIT=Y
    strMobileEdit = Request.QueryString["MEDIT"];
    if (strMobileEdit != null)
    {
        if (strMobileEdit.ToUpper() == "Y")
        {
            ActiveForm = frmEdit;
        }
    }
    

    Visual Basic.NET

    ' Switch to edit form if MEDIT=Y
    strMobileEdit = Request.QueryString("MEDIT")
    If Not strMobileEdit Is Nothing Then
         If strMobileEdit.ToUpper() = "Y" Then
                ActiveForm = frmEdit
         End If
    End If
    
  26. Add the following declaration immediately prior to the Page_Load method:

    Visual C#

    protected string strMobileEdit;
    

    Visual Basic.NET

    Protected strMobileEdit As String
    
  27. Rebuild the MobileCMS project to check for any compile errors.
  28. Rebuild the WoodgroveNet (for C# users) or WoodgroveNetVB (for Visual Basic users) project.
  29. The Mobile Web Form should now be ready to allow for login and content update. The form should appear on your mobile device as in the following figure (note the Login link):

    Figure 8. Form view on mobile device

  30. If you click on the Login link, the form will appear as in the following figure (note that if your MCMS environment has more than one domain to authenticate against, you will also see a domain selection list):

    Figure 9. Form view after you click the Login link

    Log in as an Administrator. You will return to the Job Posting form which will appear as follows (note the Edit link):

    Figure 10. Job Posting form

  31. Click the Edit link. You will be presented with the following view:

    Figure 11. Job Posting form in Edit view

  32. In the Job Title text box, change the word Assistant to Analyst, and then click Submit.

    Since you are logged in as an Administrator, your changes will be automatically approved. (If you were only logged in as an Author then an Editor, Channel Manager, or Administrator would have to approve your content submission.) You will return to display mode on the page, with the following view:

    Figure 12. Form view after edit

Conclusion

This document has illustrated the use of the Microsoft Mobile Internet Toolkit (MMIT) in conjunction with Microsoft Content Management Server (MCMS) 2002, both for content browsing and for a limited level of content modification from mobile devices.

The primary power of the MMIT is in the automatic adaptation of content rendering for mobile devices, eliminating the need for the Web designer to be concerned with the differences in syntax between HTML, WML, and cHTML. Without MCMS, the content on MMIT Mobile Web Forms must either be created manually in the Visual Studio .NET IDE, or the Mobile Web Form must programmatically access content from another data source. With MCMS, the MMIT is used simply to create templates, and content is inserted through the publishing process – either via template switching or automatic posting creation.

The example presented in this document illustrates the use of dynamic template switching to automatically detect the mobile device and redirect from the default posting template to a Mobile Web Form, populating the form's controls with MCMS placeholder content. Neither connected postings nor additional mobile—device—dedicated channels are required in this scenario. There will be some cost in server resources to implement this solution, as any mobile device access of the switched template will involve the server loading two templates – the original posting's template and the mobile template.

There were quite a few steps presented in this example. However, once this infrastructure is implemented and you review the code, you should find it relatively simple to extend this approach across your site.

If you would prefer to support mobile devices through the use of connected postings (automatically published with the original postings' creation), review the code in the following appendix ("Automatic Posting Creation").

Appendix – Automatic Posting Creation

The "MCMS 2002 Help" documentation which is installed with MCMS 2002 contains a section on Customizing the Publishing Workflow. With MCMS 2002 in ASP.NET, you have access to publishing events. (In ASP mode, you do not have access to publishing events, but rather have access to workflow hooks. As this document focuses on ASP.NET, workflow hooks are not discussed here.) Through the use of publishing events you can trigger custom actions to occur at each step of the publishing process. You should review this documentation to understand how to customize publishing events.

In this section a simple example is included that creates a connected posting using a connected template, in a separate channel called "Mobile". In actual practice, you must design logic to determine a parallel channel to the original posting's channel where the mobile content will be posted.

The example code presented here assumes that:

  • The web.config file contains the required HttpModules definitions to implement the modified events. (The WoodgroveNet solution has these events pre—configured.)
  • The Mobile channel is available as a sub—channel to the WoodgroveNet channel.
  • A corresponding Mobile template is available.

The following code, inserted in global.asax, will automatically create the connected posting when the original posting is created. The connected posting is created using a template of the same name with the characters " (Mobile)" appended. (Note: in the WoodgroveNet sample, this code will replace the existing CmsPosting_Created method.)

Please note that the code requires a reference to the Microsoft.ContentManagement.Publishing namespace:

Visual C#

using Microsoft.ContentManagement.Publishing;

Visual Basic.NET

Imports Microsoft.ContentManagement.Publishing

Replace the current CmsPosting_Created method with the following code:

Visual C#

protected void CmsPosting_Created( Object sender, CreatedEventArgs e )
{
    // Get the MCMS HTTP context.
    CmsHttpContext cxhCms = CmsHttpContext.Current;

    // Get the posting being created.
    Posting poCurrent = (Posting)e.Target;

    // Get the posting's template.
    Template tmCurrent = poCurrent.Template;

    // Get connected template collection.
    TemplateCollection tcAlternates = tmCurrent.ConnectedTemplates;

    // Select the mobile template from
    // the collection.
    Template tmMobile = tcAlternates[tmCurrent.Name + " (Mobile)"];

    // If the mobile template exists, create
    // a connected posting.
    if(tmMobile != null)
    {
        // Get the target channel.
        Channel chMobile = 
        (Channel)cxhCms.Searches.GetByPath("/Channels/WoodgroveNet/Mobile");
        if(chMobile != null)
        {
            // Create the connected posting.
            Posting poConnected = chMobile.CreateConnectedPosting(tmMobile, poCurrent);
        }
    }
}

Visual Basic.NET

Protected Sub CmsPosting_Created(ByVal sender As Object, ByVal e As CreatedEventArgs)
    ' Get the MCMS HTTP Context.
    Dim cxhCms As CmsHttpContext = CmsHttpContext.Current

    ' Get the posting being created.
    Dim poCurrent As Posting = e.Target

    ' Get the posting's template.
    Dim tmCurrent As Template = poCurrent.Template

    ' Get connected template collection.
    Dim tcAlternates As TemplateCollection = tmCurrent.ConnectedTemplates

    ' Select the mobile template from
    ' the collection.
    Dim tmMobile As Template = tcAlternates(tmCurrent.Name + " (Mobile)")

    ' If the mobile template exists, create
    ' a connected posting.
    If Not tmMobile Is Nothing Then
         ' Get the target channel.
         Dim chMobile As Channel = cxhCms.Searches.GetByPath("/Channels/WoodgroveNetVB/Mobile")
         If Not chMobile Is Nothing Then
                ' Create the connected posting.
                Dim poConnected As Posting = chMobile.CreateConnectedPosting(tmMobile, poCurrent)
         End If
    End If
End Sub

To test this code, rebuild the solution and create a new Job Posting page in the Careers channel in WoodgroveNet. A connected posting with the mobile template will be created in the Mobile channel.

Show: