XAML (SheerUI) dialog in Sitecore 6.3.x

One of my recent projects have been a Sitecore Extensions package containing some of our most common tools for Sitecore, and one of these tools is a button to manually start a scheduled task (no more waiting with the debugger running). At the same time I created a dialog where you can see all the properties of the currently selected scheduled task:

Scheduled Task Info XAML dialog

Scheduled Task Info XAML dialog

I have always found XAML (SheerUI) in Sitecore to be too time consuming and too difficult to develop. But this dialog is not that hard, as it is just a dialog with no user interaction (apart from the OK button, and I get the code for free for that one).

Here is how you do it:

First you need a command that is attahced to a button in the Sitecore shell. In this example I will even add my button as a Contextual Ribbon. Go to the CORE database and find the contextual ribbons at /sitecore/content/Applications/Content Editor/Ribbons/Contextual Ribbons:

Adding a contextual ribbon command

Adding a contextual ribbon command

You add your ribbon by creating a Toolbar, Strip, Chunk, and Large Button. Then attach the contextual ribbon onto the template:

Adding Ribbon to a Template

Adding Ribbon to a Template

Now Sitecore is almost ready to take your code.  You need to add the command to the web.config file. This is easily done by creating an .include file and add it to the /App_Config/Include folder:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:x="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <commands>
      <command name="pt:showscheduledtaskinfo" type="PT.ScheduledTasks.Commands.ShowScheduledTaskInfo, PT.ScheduledTasks" />
    </commands>
  </sitecore>
</configuration>

Now we are ready to code. First the command, ie the action that takes place when clicking the button. This command should call our XAML dialog with the current item as parameters:

namespace PT.ScheduledTasks.Commands
{
  public class ShowScheduledTaskInfo : Command
  {
    public override void Execute(CommandContext context)
    {
      Assert.ArgumentNotNull(context, "context");
      Item[] items = context.Items;
      if (items.Length == 1)
      {
        UrlString str = new UrlString(UIUtil.GetUri("control:ScheduledTaskInfo"));
        Item item = items[0];
        str["id"] = item.ID.ToString();
        str["la"] = item.Language.ToString();
        str["vs"] = item.Version.ToString();
        SheerResponse.ShowModalDialog(str.ToString());
      }
    }
  }
}

Now, here is something to explain. What does control:ScheduledTaskInfo mean? This is part of the Sitecore reflection magic, as my XAML dialog has the tag ScheduledTaskInfo in it. Sitecore will scan your entire website looking for XML files that look like XAML definitions and index all of them using their tag names. The function UIUtil.GetUri() returns the actual path to the XAML file. 
The rest of the code simply adds the item ID, Language and Version to the Querystring, and the SheerResponse function opens the dialog in a modal window.

Now we will develop the XAML dialog.

The XAML dialog consists of a XML file, and a codebeside file.

You can place the XML file anywhere on your website, Sitecore will find it. This is my dialog (not the complete info dialog as shown above, you’ll have to pay for that one :-)):

<?xml version="1.0" encoding="utf-8" ?>
<control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense">
  <ScheduledTaskInfo>
    <FormDialog Icon="People/16x16/clock_run.png" Header="Scheduled Task Info" Text="View the status of the current scheduled task." CancelButton="false">
      <Stylesheet Src="/sitecore/shell/Applications/Content Manager/Dialogs/Properties/Properties.css" />
      <CodeBeside Type="PT.ScheduledTasks.Presentation.ScheduledTasksInfoForm,PT.ScheduledTasks"/>
      <GridPanel Height="100%" Width="100%" Fixed="true">
        <Scrollbox ID="Summary" Width="100%" Height="100%" GridPanel.Style="padding:14px 4px 0px 4px" GridPanel.Height="100%">
          <GridPanel Columns="2" Cellpadding="2">
            <Literal Text="Name:" GridPanel.VAlign="top" GridPanel.NoWrap="true"/>
            <Literal ID="Name" GridPanel.VAlign="top"/>
          </GridPanel>
        </Scrollbox>
      </GridPanel>
    </FormDialog>
  </ScheduledTaskInfo>
</control>

Here is what you need to look for:
The <ScheduledTaskInfo> tag identifies this to be my Scheduled Task Dialog, and is the tag that my command uses to find the dialog.
The <FormDialog> tag identifies this as a dialog, and includes the top bar and the OK button, so you won’t need to add these manually.
The <CodeBeside> tag identifies where the dialog will look for the code that makes up the functionality.
The <GridPanel> creates the form where the contents can be placed.
The <ScrollBox> creates the white area where the labels are placed.
Each label is a <Literal>, give the label an ID to programatically alter it’s contents.

This is my codebeside file:

namespace PT.ScheduledTasks.Presentation
{
  public class ScheduledTasksInfoForm : DialogForm
  {
    // Define each control that you wish to
    // programatically alter the contents or
    // behaviour of
    protected Literal Name;
    protected Scrollbox Summary;

    // A place to put the current item
    private ScheduleItem _scheduleItem;

    protected override void OnLoad(EventArgs e)
    {
      Assert.ArgumentNotNull(e, "e");
      base.OnLoad(e);
      if (!Context.ClientPage.IsEvent)
      {
        // Grab the item from the Query String
        _scheduleItem = new ScheduleItem(GetCurrentItem());
        // Write your text to the labels
        Name.Text = _scheduleItem.Name;
        // ... more labels
      }
    }

    private Item GetCurrentItem()
    {
      // Parse the querystring to get the item
      string queryString = WebUtil.GetQueryString("id");
      Language language = Language.Parse(WebUtil.GetQueryString("la"));
      Version version = Version.Parse(WebUtil.GetQueryString("vs"));
      return Client.ContentDatabase.GetItem(queryString, language, version);
    }
  }
}

A little explanation: 
The codebeside file inherits from the DialogForm, because my XML file defines a FormDialog. This gives the OK button click code for free.
Each control that you wish to alter must be included with matching names. If your XML file contains a Literal with id “Name”, your codebeside file should contain the same Literal.
Each user interaction results in a postback, including the click on the OK button. Therefore use the !Context.ClientPage.IsEvent to isolate code.

Here you go. Not that hard after all.

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in General .NET, Sitecore 6 and tagged , , , , , , . Bookmark the permalink.