Sheer UI: 1 - A Tale of Two Systems

January 05, 2014

 

Preface

My journey began with a rebuild of a Sheer UI Wizard. I didn't build it, but I was about to learn to. After finding a dearth of literature on Sheer and realizing the documentation was a little out of date (I'm guessing SC 4), I knew I was going to write something on it. When I began writing I thought I knew a fair amount about Sheer from my experience creating different utilities but as it turns out, I knew very little. Though, from some of the applications I've seen, there seems to be a few who have faced the abyss and become steely Sheer developers, I'm betting there are more like myself with passable knowledge but not the whole picture. There was a recently released video walkthrough from the 24 hours of Sitecore led by Robert Hock that details setting up a Sheer UI application that's also worth watching and a video of the presentation I gave to the Sitecore User Group.

I should mention that Sitecore is currently moving away from Sheer toward using Speak for a UI framework. It's initial release is in Sitecore 7.1 but up until you make it there or for backward compatibility with existing tools, you'll still need to work with Sheer. 

Sheer UI

So what is Sheer UI? Sitecore, in all their industry, built a framework that is used for creating the UI of Sitecore itself. The applications, development tools, security editors among other things are built using XML Controls, although there are a few .aspx pages used also. They work similar to .NET pages in that they have a front and back end file, page lifecycle and events that you can work with. You can add to Sitecore's UI by creating your own XML controls for use in Applications, Item Editor Tabs, Rich Text Editor Buttons, overriding the existing controls and an infinite number of other ways.

XML Controls

XML controls are structured presentation XML markup and can also reference a class for functionality. Each XML node in that control, after the first and second root nodes are references to other XML controls or library web controls. Sitecore supports having more than one XML control per file but it's recommended to separate them into individual files. Sitecore stores it's controls in two locations: /sitecore/shell/Applications and /sitecore/shell/Controls

Now here's where the world that I knew, began to look like a pale blue dot. There really are two supported types of XML control syntax: The original "controls" and the newer "xamlControls". For the release of version 5.3, Sitecore redesigned how they managed XML controls altogether and added a new handler extension to resolve the new compilation model. There was also a XamlSharp.config file that exposed configuration options for many settings including the compiler itself. There was a lot of thought put into it and it was big improvement but I'm aware of no documentation for it.

Structure

So what do these XML controls look like? Here's an example of the original "control" type using common elements:

<control 
     xmlns:def="Definition" 
     xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense"> 

     <ControlName> 
          <Stylesheet Src="/sitecore modules/shell/YourApplication/css/style.css"/> 
          <Script Src="/sitecore modules/shell/YourApplication/js/script.js"/> 
          <FormPage> 
               <CodeBeside Type="Namespace.Class,Assembly"/> 
               <GridPanel Height="100%" Width="100%" runat="server"> 
                    <Border ID="Container" runat="server"> 
                         <Literal ID="ltl" Text="Hello" runat="server" /> 
                    </Border> 
               </GridPanel> 
          </FormPage> 
     </ControlName> 
</control> 

A "control" file's extension is .xml. It's root node name can be anything but the convention is to name it "control". On the "control" node you do need to have either of the two attributes shown in the example for Sitecore to recognize it as an XML control. The text of it should be copied verbatim.

Here's an example of the newer "xamlControl" using common elements:

<xamlControls 
     xmlns:x="http://www.sitecore.net/xaml" 
     xmlns:ajax="http://www.sitecore.net/ajax" 
     xmlns:rest="http://www.sitecore.net/rest" 
     xmlns:r="http://www.sitecore.net/renderings" 
     xmlns:xmlcontrol="http://www.sitecore.net/xmlcontrols" 
     xmlns:p="http://schemas.sitecore.net/Visual-Studio-Intellisense" 
     xmlns:asp="http://www.sitecore.net/microsoft/webcontrols" 
     xmlns:html="http://www.sitecore.net/microsoft/htmlcontrols" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

     <XamlHelloWorld x:inherits="Namespace.Class,Assembly"> 
          <Sitecore.Controls.HtmlPage runat="server"> <Stylesheet runat="server" Src="/sitecore modules/Shell/ApplicationName/css/style.css" x:placeholder="Stylesheets"/> 
               <Script runat="server" Src="/sitecore modules/Shell/ApplicationName/js/script.js" x:placeholder="Scripts"/> 
               <GridPanel Height="100%" Width="100%" runat="server"> 
                    <Border ID="Container" runat="server"> 
                         <Literal ID="ltl" Text="Hello" runat="server" /> 
                    </Border> 
               </GridPanel> 
          </Sitecore.Controls.HtmlPage> 
     </XamlHelloWorld> 
</xamlControls> 

Unlike the older "control", "xamlControls" file extensions' are .xaml.xml and their root node name must be named "xamlControls" otherwise you'll be the beneficiary of a blue screen: Xaml files must have a root node named "xamlControls". Well technically it's yellow, but blue sounded better. The attributes on the root node are used to help with intellisense and to help Sitecore know where too look for different elements. The xmlns (XML Namespace) attribute in the opening xml tag defines the prefix and the namespace. The prefix is local to that xml node in the file so it can be anything but the namespace is important. The "Definition" namespace used on "control" items were built into the early compiler but the "xamlControls" uses namespaces that are defined in the XamlSharp.config file under the <attributeAssigners> section. Now I'm still a little fuzzy on the entirety of the inner workings of how the compiler uses all these elements to build controls but from the limited time I have, that seems to be what's going on.

For both types of controls, the first child of the root node is where the control name is defined. The name is important since Sitecore references the control by name. Each control should have a unique name because if there are duplicates only the first one found by Sitecore will be used and the rest will be ignored. In regular use, since control names should be unique, it may be advantageous to name the control with a namespace which appears to be the convention on newer controls.

You should understand how each types loads supporting classes. The "control" and "xamlControl" types can use def:inherits or x:inherits respectively. Also the "control" types support the <CodeBeside> tag to define a class but the "xamlControl" does not. I'm not sure why this is so, since other controls in the same namespace will work but I'm chalking this one up to the inner mysteries of the compiler. One thing I do know is that neither the "control" nor the "xamlControl" support each other's type as an inner control. Take the use of the <FormPage> and <Sitecore.Controls.HtmlPage> controls as an example. The <FormPage> is a "control" type that lives here: /sitecore/shell/controls/Standard/Form Page.xml and the <Sitecore.Controls.HtmlPage> is a "xamlControls" type that lives here: /sitecore/shell/Applications/Xaml/Controls/HtmlPage.xaml.xml. You could not use the <Sitecore.Controls.HtmlPage> in a "control" nor could you use the <FormPage> in a "xamlControl".

Rendering

Another improvement made, was how Sitecore loads the control. For both methods you will need to be logged in to use the tools because they both run on the shell website.

"controls" can be previewed by the url: http://localhost/sitecore/shell/default.aspx?xmlcontrol=CaseSensitiveControlName 

"xamlControls" can be viewed by the handler url: http://localhost/sitecore/shell/~/xaml/ControlName.aspx. In some contexts in Sitecore, there are also querystring parameters such as: ID, Language, Version and Database. This handler url is configured in the <customHandlers> Sitecore section of the web.config.  

When you load a Sheer XML control, Sitecore, after first checking for the control in cache, will convert the control into an interim class file that inherits fromSitecore.Web.UI.XmlControls.XmlControl for "control" types and Sitecore.Web.UI.XamlSharp.Xaml.XamlControl for "xamlControls" respectively. This class is then compiled into its own assembly, an instance created and then rendered to a page. The compiled classes only recompile when the XML file is modified sufficiently, allowing you the flexibility of modifying the layout without having to recompile your project.

Configuration

There's a few web.config settings that can be set to modify XML control behavior in your system. I'm not sure if this is universal to both systems or not.

  • disableXmlControls (<sites>): If set to true, loading Xml Controls as pages will be disabled.
  • XmlControls.ThrowException (<settings>): Specifies if an exception is thrown when an Xml Control can't be loaded. Errors are written to the log.
  • XmlControls.OutputDebugFiles (<settings>) : If true, the *.cs files will be saved in to the debug folders associated with the XmlControls

"control" configuration

If you're working with the original "control" types, you can optionally configure the using statements, assemblies and control sources that Sitecore will insert when converting the XML controls into classes. Here's the sitecore web.config sections where you can manage these settings:

  • /sitecore/ui/using
  • /sitecore/ui/references
  • /sitecore/controlSources

Sitecore uses the sitecore/controlsources section of the web.config to define what libraries and folders are used to search for the controls used in an XML file. The default web.config includes these namespaces:

  • Sitecore.Web.UI.HtmlControls
  • Sitecore.Web.UI.WebControls
  • Sitecore.Shell.Web.UI.WebControls
  • Sitecore.Shell.Applications.ContentEditor
  • Sitecore.Shell.Web.Applications.ContentEditor
  • Sitecore.WebControls
  • System.Web.UI.WebControls
  • System.Web.UI.HtmlControls
  • Sitecore.Web.UI.Portal
  • ComponentArt.Web.UI

 and loads XML control files from these directories:

  • /sitecore/shell/override
  • /layouts
  • /sitecore/shell/controls
  • /sitecore/shell/applications
  • /sitecore modules

"xamlControls" Configuration

If you're working with the new "xamlControls" there is an /App_Config/XamlSharp.config file where settings are configured. One of the improvements using this newer system is that, similar to many other aspects of Sitecore, you have the ability to override Sitecore's default behavior such as the control compilers. You can also define custom folders and namespaces where controls can be used from. I'll give a brief rundown on what each section controls.

Compilers

The compilers sections defines the class that renders the XML Control files into a renderable control. This is where Sitecore has the ability to inject a handful of attribute features, such as class overriding and passing in parameters

ControlCompilers

The control compilers are the definitions of classes that are used to find the library control to use to render each control tag type in the XML markup.

Extensions

Extensions are custom tags that affect the control you're working on. The extensions can modify the attributes on the parent control, provide xsl-like if/else/for-each controls and even set local parameters.

AttributeAssigners

Attribute Assigners allow you to set attributes that aren't properties on the control but will be rendered by the Sitecore's compiler.

AttributeEvaluators

Attribute Evaluators allow you to write c# expressions inside attribute tags that get rendered when the control is compiled.

Sources

Sources define the folders and class libraries that are used to support the controls used in the XML.

The default XamlSharp.config namespaces included are:

  • Sitecore.Web.UI.HtmlControls
  • Sitecore.Web.UI.WebControls
  • System.Web.UI.WebControls
  • System.Web.UI.HtmlControls

and it includes these folder paths for Xaml Controls:

  • /sitecore/shell/Applications
  • /sitecore modules

DefinitionCreators

Definition Creators define the file extension that is used to identify XML controls.

HtmlControls

Html Controls are the html tags and what library control is used to render them. Anything that isn't defined on the list, should pass through as is.

Creating Custom Controls

When you create XML controls, consider putting them in your own folder under /sitecore modules/shell/ folder, which is already included by the web.config and XamlSharp.config. And for consistency, try to name the file, the XML control name and class name the same, otherwise it will be confusing to use.

The preferred base class for "control" types were Sitecore.Web.UI.Sheer.BaseForm and the preferred base class for "xamlControls" isSitecore.Web.UI.XamlSharp.Xaml.XamlMainControl.

You can create your own types or new folder locations, just make sure to update the web.config or XamlSharp.config to reference your library or folder so that Sitecore knows to look there for them. Since, as I previously mentioned, Sitecore references controls by their names and will use the first it finds, ignoring duplicates, you could override existing controls with your own by placing the config reference to your folders before the existing references.

Tutorial Sample

There is a tutorial Xaml control that lives under /sitecore/shell/Applications/Xaml. The url to view the control in action is this:http://localhost/sitecore/shell/~/xaml/Sitecore.Xaml.Tutorials.Index.aspx. Some of the pages were throwing exceptions which I was able to resolve once I removed the AjaxScriptManager control from the page. This, of course, breaks the ajax and rest functionality but that's a bug I don't know how to fix.

There is also a sample wizard that you can view or use the source to, that lives in the same folder:http://localhost/sitecore/shell/~/xaml/Sitecore.Shell.Xaml.WebControl.aspx

Alright, now that I've explained a bit about what Sheer UI is and how it's configured in Sitecore, my next articles will go through some Hello World examples.