Playing around with Media Center and MCML

Getting a bit off subject again, I recently started playing around at home with Media Center and MCML. MCML basically allows you to create full fidelity applications using Media Center and, as I understand, is what most of the Media Center UI is created on.

 

It’s a rather strange programming language as the goal is to completely separate the UI (view) from the data (model). While this certainly isn’t anything new, here it is taken to the extreme in that many things that you would normally do in code, such as events, is done in XML. Another thing is there is no library of basic controls to build applications on – everything you need you will have to create from scratch.

 

First, a disclaimer. I work on the Unified Communications team, not in the Media Center team – so my knowledge of MCML and Media Center is limited to the same resources you can find on the web. While I do know a few people on that team, I have refused to bug them with my questions.

 

I will do a quick walkthrough of a (poorly written) application that I recently created. The goal was to create a real estate searching application as my wife is studying to be a real estate agent so that was the subject that popped out first. However, I doubt I will take this application much further than where it currently is (which is not very far).

 

The following is my opening MCML page.

 

<Mcml xmlns="https://schemas.microsoft.com/2006/mcml"

      xmlns:a="assembly://RealEstateSearcher/RealEstateSearcher"

      xmlns:multiselect="resx://RealEstateSearcher/RealEstateSearcher.Resources/MultiSelect"

      xmlns:re="assembly://RealEstateSearcher/RealEstateSearcher.Code"

      xmlns:styles="resx://RealEstateSearcher/RealEstateSearcher.Resources/Styles"

      xmlns:nav="resx://RealEstateSearcher/RealEstateSearcher.Resources/NavigationPanel"

      xmlns:cor="assembly://MSCorLib/System"

      xmlns:me="Me">

  <!-- Hello World UI -->

  <UI Name="Hello">

    <Content>

   

      <Panel>

        <Children>

          <Graphic Layout="Center" Content="image://styles:BackgroundImage">

            <Children>

              <multiselect:MultiSelect>

                <Model>

                  <!-- Test model: an option with three values -->

                  <re:MultiChoice Description="My Radio Group">

                    <Options>

                      <re:MultiChoiceItem Title="Beaux Arts" />

                      <re:MultiChoiceItem Title="Bellevue" />

                      <re:MultiChoiceItem Title="Bothell" />

                      <re:MultiChoiceItem Title="Carnation" />

                      <re:MultiChoiceItem Title="Clyde Hill" />

                      <re:MultiChoiceItem Title="Duvall" />

                      <re:MultiChoiceItem Title="Hunts Point" />

                      <re:MultiChoiceItem Title="Issaquah" />

                      <re:MultiChoiceItem Title="Kenmore" />

                      <re:MultiChoiceItem Title="Kirkland" />

                      <re:MultiChoiceItem Title="Medina" />

                      <re:MultiChoiceItem Title="Mercer Island" />

                      <re:MultiChoiceItem Title="Newcastle" />

                      <re:MultiChoiceItem Title="Redmond" />

                      <re:MultiChoiceItem Title="Renton" />

     <re:MultiChoiceItem Title="Sammamish" />

                      <re:MultiChoiceItem Title="Woodinville" />

                      <re:MultiChoiceItem Title="Yarrow Bay" />

                    </Options>

                  </re:MultiChoice>

                </Model>

              </multiselect:MultiSelect>

            </Children>

          </Graphic>

        </Children>

      </Panel>

     

    </Content>

  </UI>

</Mcml>

 

For those of you who have used XAML the top will look very familiar. Basically I am just imported other classes so I can use them in this file. The UI element specified what can be considered a control or a page. There are four possible child elements of the UI element and I use only one here – Content – which is basically what should appear on the screen.

 

Content can have only one child, so I used a panel to arrange things on the screen and then I set a background image under that. Finally, I reference a MultiSelect object that I created and pass it in data. The code for MultiSelect is data related so it is written in C#.

 

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text;

using Microsoft.MediaCenter.UI;

namespace RealEstateSearcher.Code

{

    /// <summary>

    /// Handles the model for a list of values where multiple values can be selected

    /// </summary>

    public class MultiChoice : ModelItem, IValueRange

    {

        #region Private member variables

        private string _title;

        private List<string> _chosenOptions;

        private IList _options;

        private int _currentIndex;

        #endregion

        #region Constructor

        /// <summary>

        /// Creates a new MultiChoice instance

        /// </summary>

        public MultiChoice()

  {

            _chosenOptions = new List<string>();

            _currentIndex = 0;

        }

        #endregion

        #region Properties

       

        /// <summary>

        /// The description of the choice

        /// </summary>

        public string Title

        {

            get

            {

                return _title;

            }

            set

            {

                if (_title != value)

                {

                    _title = value;

                    FirePropertyChanged("Title");

                }

            }

        }

        /// <summary>

        /// The list of options available

        /// </summary>

        public IList Options

        {

            get

            {

                return _options;

            }

            set

            {

                if (_options != value)

                {

                    _options = value;

                    FirePropertyChanged("Options");

                }

            }

        }

        /// <summary>

        /// Returns a string representing the selected options

        /// </summary>

        public string SelectedOptions

        {

            get

            {

                return String.Join(", ", _chosenOptions.ToArray());

            }

        }

        /// <summary>

        /// The text used to specify the items the user selected

        /// </summary>

        public string SelectText

        {

            get

            {

                if (_chosenOptions.Count == 0)

                {

                    return Resources.No_Option_Selected;

                }

                else if (_chosenOptions.Count == 1)

                {

                    return Resources.Single_Option_Selected;

                }

                else

           {

                    return Resources.Multi_Option_Selected;

                }

            }

        }

        #endregion

        #region Methods

        /// <summary>

        /// Toggles the specified selection

        /// </summary>

        /// <param name="selection">The selection to toggle</param>

        public void ToggleSelection(string selection)

        {

            // See if we are adding or removing the selection

            if (true == _chosenOptions.Contains(selection))

            {

                // Remove the option

                _chosenOptions.Remove(selection);

            }

            else

            {

                // Add the option

                _chosenOptions.Add(selection);

            }

            FirePropertyChanged("SelectedOptions");

            FirePropertyChanged("SelectText");

        }

        #endregion

        #region IValueRange Members

        /// <summary>

        /// Returns true if we have a next value

        /// </summary>

        public bool HasNextValue

        {

            get

            {

                if (_currentIndex < _options.Count)

                {

                    return true;

                }

                else

                {

                    return false;

                }

            }

        }

        /// <summary>

        /// Returns true if we have a previous value

        /// </summary>

        public bool HasPreviousValue

        {

            get

            {

                if (_currentIndex > 0)

                {

                    return true;

                }

                else

                {

                    return false;

                }

            }

        }

        /// <summary>

        /// Moves to the next value

        /// </summary>

        public void NextValue()

        {

            _currentIndex++;

        }

        /// <summary>

        /// Moves to the previous value

        /// </summary>

        public void PreviousValue()

     {

            _currentIndex--;

        }

        /// <summary>

        /// Gets the current value

        /// </summary>

        public object Value

        {

            get

            {

                return _options[_currentIndex];

            }

        }

        #endregion

    }

}

 

Most of this code will be of use in our actual MultiSelect control. It implements IModelItem, which is required for all model objects. It is not overly complex but basically allows one to keep track of which items are selected. IValueRange is an MCML interface used by the UI to iterate through my data. When doing data binding, it is important to call FirePropertyChanged to alert the UI that the value has changed. The following is the MCML for my MultiSelect, which displays the UI.

 

<Mcml

  xmlns="https://schemas.microsoft.com/2006/mcml"

  xmlns:re="assembly://RealEstateSearcher/RealEstateSearcher.Code"

  xmlns:cor="assembly://MSCorLib/System"

  xmlns:checkbox="resx://RealEstateSearcher/RealEstateSearcher.Resources/Checkbox"

  xmlns:button="resx://RealEstateSearcher/RealEstateSearcher.Resources/Button"

  xmlns:styles="resx://RealEstateSearcher/RealEstateSearcher.Resources/Styles"

  xmlns:me="Me">

 

  <!--  Implements a multi select control consisting of multiple checkboxes -->

  <UI Name="MultiSelect" >

    <Properties>

      <re:MultiChoice Name="Model" MultiChoice="$Required" />

      <!-- These anchors represent the two places we could position -->

  <!-- our scroll arrows. -->

      <AnchorLayoutInput Name="AlignToTop"

                        Top="Scroller,0,-100" Bottom="Scroller,0,-15" Vertical="Far"

                        Left="Scroller,0" Right="Scroller,1" Horizontal="Center"

                        ContributesToHeight="false"/>

      <AnchorLayoutInput Name="AlignToBottom"

                        Top="Scroller,1,15" Bottom="Scroller,1,100" Vertical="Near"

                        Left="Scroller,0" Right="Scroller,1" Horizontal="Center"

                        ContributesToHeight="false"/>

    </Properties>

     

    <Rules>

      <!-- Bind the selected choice to the 'Selection' text element. -->

      <Binding Source="[Model.SelectedOptions!cor:String]" Target="[Selection.Content]" />

      <!-- Bind the sample data as a source to the repeater. -->

      <Binding Source="[Model.Options]" Target="[Repeater.Source]" />

     

      <!-- Display text corresponding to the number of items selected -->

      <Binding Source="[Model.SelectText]" Target="[SelectText.Content]" />

      <!-- Give ScrollingData to ScrollingHandler. -->

      <Default Target="[ScrollingHandler.ScrollingData]" Value="[ScrollData]"/>

      <!-- Give Repeater to ScrollingData. -->

      <Default Target="[ScrollData.Repeater]" Value="[Repeater]"/>

      <Default Target="[Repeater.Source]" Value="[Model.Options]" />

     

      <!-- Only show the scroll buttons if we can scroll in that direction -->

      <Binding Source="[ScrollData.CanScrollUp]" Target="[ScrollUpButton.Visible]"/>

      <Binding Source="[ScrollData.CanScrollDown]" Target="[ScrollDownButton.Visible]"/>

      <!-- Scroll up/left -->

      <Changed Source="[ScrollUp.Invoked]">

        <Actions>

          <Invoke Target="[ScrollData.PageUp]"/>

        </Actions>

      </Changed>

      <!-- Scroll down/right -->

      <Changed Source="[ScrollDown.Invoked]">

        <Actions>

          <Invoke Target="[ScrollData.PageDown]"/>

        </Actions>

      </Changed>

    </Rules>

    <Locals>

      <!-- The ScrollingHandler which reacts to user keyboard input. -->

      <!-- Turn on handing of arrow keys for scrolling (not on by -->

      <!-- default). -->

      <!-- NOTE: HandlerStage must be "Direct" (which is default). -->

      <ScrollingHandler Name="ScrollingHandler" HandlerStage="Bubbled" HandleDirectionalKeys="true"/>

      <!-- ScrollingData contains many ways to customize how scrolling -->

      <!-- should behave. It has methods to change the current scroll -->

      <!-- position and it also reports the position. In this case, -->

      <!-- the default values are used for the sample. -->

      <ScrollingData Name="ScrollData"/>

      <!-- Scroll actions -->

      <Command Name="ScrollUp" Description="Up"/>

      <Command Name="ScrollDown" Description="Down"/>

      <ArrayListDataSet Name="DataSet" />

    </Locals>

   

    <Content>

      <!-- The scrolling list of choices-->

      <Panel Layout="Anchor">

        <Children>

         

          <!-- Text element to display the usage information. -->

          <Text Name="TopText" Content="resx://RealEstateSearcher/RealEstateSearcher.Resources/MultiSelect_Top_Title"

                Color="LightGray" Font="font://styles:SectionTitle" Padding="0,0,0,20">

            <LayoutInput>

              <AnchorLayoutInput Top="Parent,.10" Left="Parent,.1" />

            </LayoutInput>

          </Text>

          <Panel Name="SecondText">

            <Layout>

              <FlowLayout Orientation="Horizontal" Spacing="5,0" AllowWrap="true"/>

            </Layout>

            <LayoutInput>

              <AnchorLayoutInput Top="TopText,1,5" Left="Parent,.1" />

            </LayoutInput>

            <Children>

              <!-- Text elements to show the choice selection. -->

              <Text Name="SelectText" Color="LightGray"

                    Font="font://styles:SecondaryText" Margins="0,0,0,30" />

              <Text Name="Selection" Color="Red" Font="font://styles:SecondaryText"

                    Margins="0,0,0,30" WordWrap="true"/>

            </Children>

          </Panel>

         

          <!-- Scroll up -->

          <me:ScrollButton Name="ScrollUpButton" Model="[ScrollUp]"

            Image="resx://RealEstateSearcher/RealEstateSearcher.Resources/MouseNavUp" FocusImage="resx://RealEstateSearcher/RealEstateSearcher.Resources/MouseNavUpFocus"

            LayoutInput="[AlignToTop]"/>

          <!-- Scroll down -->

          <me:ScrollButton Name="ScrollDownButton" Model="[ScrollDown]"

            Image="resx://RealEstateSearcher/RealEstateSearcher.Resources/MouseNavDown" FocusImage="resx://RealEstateSearcher/RealEstateSearcher.Resources/MouseNavDownFocus"

            LayoutInput="[AlignToBottom]"/>

          <!-- Scrolling area -->

          <Scroller Name="Scroller" Orientation="Vertical"

              ScrollingData="[ScrollData]" FadeSize="-5">

            <LayoutInput>

              <AnchorLayoutInput Top="SecondText,1,5" Left="Parent,.1"/>

            </LayoutInput>

            <Children>

              <!-- Content repeater -->

              <Repeater Name="Repeater" Source="[DataSet]" ContentName="CheckBoxItem">

                <Layout>

                  <GridLayout Orientation="Vertical" Columns="1"

                        Spacing="10,10" AllowWrap="false"/>

                </Layout>

                <Animations>

                  <!-- Scrolling animation -->

                  <Animation Type="Move">

                    <Keyframes>

         <PositionKeyframe Time="0.00" RelativeTo="Current"/>

                      <PositionKeyframe Time="0.25" RelativeTo="Final"/>

                    </Keyframes>

                  </Animation>

                </Animations>

              </Repeater>

            </Children>

          </Scroller>

         

        </Children>

      </Panel>

        

    </Content>

    <Content Name="CheckBoxItem">

      <checkbox:CheckBox Model="[Model]" Option="[RepeatedItem!re:MultiChoiceItem]" />

    </Content>

  </UI>

  <!-- A list scroll button -->

  <UI Name="ScrollButton" BaseUI="button:Button">

    <Properties>

      <Size Name="TileMinSize" Size="0,0"/>

      <Size Name="TileMaxSize" Size="20,20"/>

    </Properties>

    <Rules>

      <!-- Mouse interactive only -->

      <Default Target="[Input.KeyInteractive]" Value="false"/>

      <!-- No label -->

      <Default Target="[Label.Visible]" Value="false"/>

      <Default Target="[Background.SizingPolicy]" Value="SizeToConstraint"/>

      <!-- Mouse focused styling -->

      <Condition Source="[Input.MouseFocus]" SourceValue="true">

        <Actions>

          <Set Target="[Background.Content]" Value="[FocusImage]"/>

        </Actions>

      </Condition>

    </Rules>

  </UI>

</Mcml>

 

Here I specify other possible child elements of the UI element. The Properties child allows me to create variables that are subject to change. If the value is set to $Required it must be passed in but I can pass the value to any of these I desire. If you scroll back up to the default page you will see that I pass in the value of Model, which is required. The AnchorLayoutInput elements are just shortcuts for later and specify that those elements should be aligned to the top of the parent or to the bottom.

 

The Rules section allows me to specify bindings and event handlers. The Default element allows me to give an element a default value. Here I have several elements that specify the data from the C# code I showed above is used to populate a scrolling repeater element – which is how data lists are displayed in MCML. The event handlers here handle the case of the scroll up and scroll down buttons being clicked and scroll up or down as appropriate.

 

The Locals section allows us to specify variables not subject to change through the page. Here I have some command objects that handle the clicking of my up and down scroll buttons.

 

In the Panel of my Content element, I specify a layout of Anchor which allows me to specify the location of an item relative to its parent. I found it a bit tricky to get the hang of but eventually my controls ended up where I wanted them. Basically here I display two rows of text – where the first is just some static text saying what the user should do and the second displays the user’s selections. Finally I have a Scroller item that displays the data from my model. The Repeater is what actually handles the data and you can see below the Scroller I call a CheckBox element that I will get to shortly. Note that even though the Scroller and Repeater handle scrolling data, I still need to add the scroll buttons myself.

 

I placed the XML for the ScrollButton element within the same file at the bottom. It derives from the button element that I will also cover shortly. Basically here I set some common properties for the buttons and handle mouse focusing. I also keep it from the keyboard.

 

The code for button is a bit simpler than checkbox so I will cover that next.

 

<Mcml

      xmlns="https://schemas.microsoft.com/2006/mcml"

      xmlns:sys="assembly://mscorlib/System"

      xmlns:styles="resx://RealEstateSearcher/RealEstateSearcher.Resources/Styles"

      xmlns:me="Me">

  <UI Name="Button">

    <Properties>

      <!-- The action that will be invoked when this button is pressed -->

      <ICommand Name="Model" ICommand="$Required"/>

      <!-- Button label properties -->

      <Color Name="TextColor" Color="color://styles:Text.Active"/>

      <Color Name="TextFocusColor" Color="color://styles:Text.Negative"/>

      <Color Name="TextSelectedColor" Color="color://styles:Text.Copy"/>

      <Font Name="TextFont" Font="font://styles:SecondaryText"/>

      <Inset Name="TextMargins" Inset="8,-2,8,2"/>

      <sys:Boolean Name="CenterText" Boolean="false"/>

      <!-- Tile metrics -->

      <Size Name="TileMinSize" Size="0,32"/>

      <Size Name="TileMaxSize" Size="300,32"/>

      <!-- Images -->

      <Image Name="Image" Image="null"/>

      <Image Name="FocusImage" Image="image://styles:ButtonFocusImage"/>

    </Properties>

    <Locals>

      <!-- Make this button clickable -->

      <ClickHandler Name="Clicker" Command="[Model]"/>

    </Locals>

    <Rules>

      <!-- Bind the button's label -->

      <Binding Source="[Model.Description]" Target="[Label.Content]"/>

      <!-- Pressed styling -->

      <Condition Source="[Clicker.Clicking]" SourceValue="true">

        <Actions>

          <!--<PlaySound Sound="sound://styles:SelectSound"/>-->

          <PlayAnimation Target="[Background]" Animation="animation://me:ButtonPress"/>

        </Actions>

      </Condition>

      <!-- Focused styling -->

      <Condition Source="[Input.KeyFocus]" SourceValue="true">

        <Actions>

          <Set Target="[Background.Content]" Value="[FocusImage]"/>

          <Set Target="[Label.Color]" Value="[TextFocusColor]"/>

          <!--<PlaySound Sound="sound://styles:FocusSound"/>-->

        </Actions>

      </Condition>

      <!-- Selected styling -->

      <Condition Source="[Model.Selected]" SourceValue="true">

        <Actions>

          <Set Target="[Label.Color]" Value="[TextSelectedColor]"/>

        </Actions>

      </Condition>

      <!-- Hook up dynamic text style properties. -->

      <Binding Source="[TextColor]" Target="[Label.Color]"/>

      <Binding Source="[TextFont]" Target="[Label.Font]"/>

      <Binding Source="[TextMargins]" Target="[Label.Margins]"/>

      <!-- Change the layout if using the "center" option -->

      <Condition Source="[CenterText]" SourceValue="true"

                        Target="[Background.Layout]" Value="Center"/>

      <!-- Accessibility -->

      <Binding Target="[Accessible.IsPressed]" Source="[Clicker.Clicking]"/>

      <Binding Target="[Accessible.IsFocusable]" Source="[Input.KeyInteractive]"/>

      <Binding Target="[Accessible.IsFocused]" Source="[Input.KeyFocus]"/>

      <Binding Target="[Accessible.Name]" Source="[Model.Description]"/>

      <Default Target="[Accessible.DefaultActionCommand]" Value="[Model]"/>

      <Default Target="[Accessible.DefaultAction]" Value="Press"/>

      <Default Target="[Accessible.Role]" Value="PushButton"/>

    </Rules>

    <Content>

      <!-- Background -->

      <Graphic Name="Background" Content="[Image]" SizingPolicy="SizeToChildren"

                              MinimumSize="[TileMinSize]" MaximumSize="[TileMaxSize]">

        <Children>

          <!-- Label -->

          <Text Name="Label" Font="[TextFont]" Color="[TextColor]" Margins="[TextMargins]"/>

        </Children>

      </Graphic>

    </Content>

  </UI>

  <!-- Animations -->

  <Animation Name="ButtonPress" Loop="0" CenterPointPercent="0.5,0.5,1.0">

    <Keyframes>

      <ScaleKeyframe Time="0.00" RelativeTo="Current" Interpolation="Log"/>

      <ScaleKeyframe Time="0.08" Value="0.9,0.9,1.0"/>

      <ScaleKeyframe Time="0.15" Value="1.0,1.0,1.0"/>

    </Keyframes>

  </Animation>

</Mcml>

 

Here you can see what I mean by the fact that you have to implement almost everything yourself. I am sorry to say now that I am running out of time to write this post so rather than leave you in the dark about the rest of the code I will just post it without explanation below. If you have any questions about it please feel free to ask – though I can’t guarantee that I know the answer. I should also reiterate that I am just a beginner in MCML so a lot of what I am doing is likely wrong. But if you’d like to get a further feel for what you can do, here is the code for checkbox.

 

<Mcml

    xmlns="https://schemas.microsoft.com/2006/mcml"

    xmlns:cor="assembly://MSCorLib/System"

    xmlns:re="assembly://RealEstateSearcher/RealEstateSearcher.Code"

    xmlns:styles="resx://RealEstateSearcher/RealEstateSearcher.Resources/Styles"

    xmlns:me="Me">

 

  <UI Name="CheckBox">

    <Properties>

      <!-- Command is a required parameter. -->

      <re:MultiChoice Name="Model" MultiChoice="$Required" />

      <re:MultiChoiceItem Name="Option" MultiChoiceItem="$Required"/>

      <Size Name="BoxSize" Size="50,50"/>

      <!-- Checked box color properties. -->

      <Color Name="CheckColor" Color="White"/>

      <Color Name="CheckFocusedColor" Color="White"/>

      <Color Name="CheckHoverColor" Color="White"/>

      <Color Name="CheckPressedColor" Color="DimGray"/>

      <!-- Label color properties. -->

      <Color Name="LabelColor" Color="color://styles:Text.Active"/>

      <Color Name="LabelFocusedColor" Color="color://styles:Text.Focused"/>

      <Color Name="LabelSelectedColor" Color="color://styles:Text.Selected"/>

     <Color Name="LabelHoverColor" Color="color://styles:Text.Focused"/>

      <Color Name="LabelPressedColor" Color="color://styles:Text.Focused"/>

      <!-- Label font property. -->

      <Font Name="LabelFont" Font="font://styles:SecondaryText"/>

    </Properties>

    <Locals>

      <!-- React to "click" input. -->

      <ClickHandler Name="Clicker"/>

    </Locals>

    <Rules>

      <!-- The command description is displayed by the text box. A -->

      <!-- binding is used in case the description changes at -->

      <!-- runtime. -->

      <Binding Source="[Option.Title]" Target="[Label.Content]"/>

      <!-- Toggle the selected value -->

      <Changed Source="[Clicker.Invoked]">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="false" />

        </Conditions>

        <Actions>

          <Invoke Target="[Model.ToggleSelection]" selection="[Option.Title]" />

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxCheckedFocus" />

          <Set Target="[Option.IsSelected]" Value="[Model.Value]">

            <Transformer>

              <BooleanTransformer Inverse="true"/>

            </Transformer>

          </Set>

        </Actions>

      </Changed>

     

      <!-- Untoggle the selected value -->

      <Changed Source="[Clicker.Invoked]">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="true" />

        </Conditions>

        <Actions>

          <Invoke Target="[Model.ToggleSelection]" selection="[Option.Title]" />

          <Set Target="[Option.IsSelected]" Value="[Model.Value]">

            <Transformer>

              <BooleanTransformer Inverse="false"/>

            </Transformer>

          </Set>

        </Actions>

      </Changed>

      <!-- Show the check when selected -->

      <Changed Source="[Option.IsSelected]">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="true" />

        </Conditions>

        <Actions>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxChecked" />

          <Set Target="[Label.Color]" Value="[LabelSelectedColor]" />

        </Actions>

      </Changed>

      <!-- Do not show the check when selected -->

      <Changed Source="[Option.IsSelected]">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="false" />

        </Conditions>

        <Actions>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxNonFocus" />

          <Set Target="[Label.Color]" Value="[LabelColor]" />

        </Actions>

      </Changed>

      <!-- Retain the check mark when not selected -->

      <Condition Source="[Clicker.Clicking]" SourceValue="false">

        <Conditions>

          <Equality Source="[Input.MouseFocus]" Value="false" />

          <Equality Source="[Input.KeyFocus]" Value="false" />

          <Equality Source="[Option.IsSelected]" Value="true" />

        </Conditions>

        <Actions>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxChecked" />

          <Set Target="[Label.Color]" Value="[LabelSelectedColor]" />

        </Actions>

      </Condition>

     

      <!-- Change color on mouse focus when checkbox is not checked. -->

      <Condition Source="[Clicker.Clicking]" SourceValue="true">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="false" />

        </Conditions>

        <Actions>

  <Set Target="[Label.Color]" Value="[LabelPressedColor]"/>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxFocus"/>

        </Actions>

      </Condition>

      <!-- Change color on mouse focus when checkbox is not checked. -->

      <Condition Source="[Input.MouseFocus]" SourceValue="true">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="false" />

        </Conditions>

        <Actions>

          <Set Target="[Label.Color]" Value="[LabelHoverColor]"/>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxFocus"/>

        </Actions>

      </Condition>

      <Default Target="[Input.KeyInteractive]" Value="true"/>

      <!-- Change color on key focus when checkbox is not checked. -->

      <Condition Source="[Input.KeyFocus]" SourceValue="true">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="false" />

        </Conditions>

        <Actions>

          <Set Target="[Label.Color]" Value="[LabelFocusedColor]"/>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxFocus"/>

        </Actions>

      </Condition>

      <!-- Change color on mouse focus when checkbox is checked. -->

      <Condition Source="[Clicker.Clicking]" SourceValue="true">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="true" />

        </Conditions>

        <Actions>

          <Set Target="[Label.Color]" Value="[LabelPressedColor]"/>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxCheckedFocus"/>

        </Actions>

      </Condition>

      <!-- Change color on mouse focus when checkbox is checked. -->

      <Condition Source="[Input.MouseFocus]" SourceValue="true">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="true" />

        </Conditions>

        <Actions>

          <Set Target="[Label.Color]" Value="[LabelHoverColor]"/>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxCheckedFocus"/>

        </Actions>

      </Condition>

      <Default Target="[Input.KeyInteractive]" Value="true"/>

      <!-- Change color on key focus when checkbox is checked. -->

      <Condition Source="[Input.KeyFocus]" SourceValue="true">

        <Conditions>

          <Equality Source="[Option.IsSelected]" Value="true" />

        </Conditions>

        <Actions>

          <Set Target="[Label.Color]" Value="[LabelFocusedColor]"/>

          <Set Target="[Check.Content]" Value="image://styles:CheckBoxCheckedFocus"/>

        </Actions>

      </Condition>

    </Rules>

    <Content>

      <Panel>

        <Layout>

          <FlowLayout Orientation="Horizontal" ItemAlignment="Center"/>

        </Layout>

        <Children>

          <!-- The box around the check -->

            <Graphic Name="Check" Content="image://styles:CheckBoxNonFocus"

                     MouseInteractive="true" Margins="0,0,5,0" MaximumSize="[BoxSize]" Layout="Form">

              <LayoutInput>

                <FormLayoutInput Left="Parent,0.2" Right="Parent,0.8"

                                 Top="Parent,0.2" Bottom="Parent,0.8"/>

              </LayoutInput>

            </Graphic>

          <!-- The label to display. -->

          <Text Name="Label" Color="[LabelColor]" Font="[LabelFont]"/>

        </Children>

      </Panel>

    </Content>

  </UI>

</Mcml>

 

Several of these pages reference a style sheet which is defined as follows.

 

<Mcml xmlns="https://schemas.microsoft.com/2006/mcml">

  <!-- These style names are taken from the Design Guidelines spec. -->

  <!-- There should be a 1-to-1 mapping to enable easy editing. -->

  <Color Name="Background.A" Color="133,146,148"/>

  <Color Name="Container.A" Color="191,130,130,130"/>

  <Color Name="Container.B" Color="191,55, 62, 64"/>

  <Color Name="Text.Copy" Color="255,255,255,255"/>

  <Color Name="Text.Active" Color="128,255,255,255"/>

  <Color Name="Text.Focused" Color="255,255,255,255"/>

  <Color Name="Text.Selected" Color="188,255,255,255"/>

  <Color Name="Text.Negative" Color="255,54,57,9"/>

  <Color Name="Accent.A" Color="255,255,255"/>

  <Color Name="Accent.B" Color="182,206,0"/>

  <!-- Fonts -->

  <Font Name="MainMenuSectionTitle" Font="Calibri Bold,48"/>

  <Font Name="SectionTitle" Font="Calibri Bold,32"/>

  <Font Name="CopyText" Font="Calibri,22"/>

  <Font Name="SecondaryText" Font="Calibri,18"/>

  <Font Name="TertiaryText" Font="Calibri,16"/>

  <Font Name="GalleryItemSubText" Font="Calibri,14"/>

  <Font Name="EditText" Font="Segoe UI,20"/>

  <Font Name="KeyboardText" Font="Segoe UI,18"/>

  <!-- Shared image resources -->

  <Image Name="BackgroundImage" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/Background" NineGrid="4,4,4,4"/>

  <Image Name="CheckBoxFocus" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/CheckBoxFocus" NineGrid="4,4,4,4"/>

  <Image Name="CheckBoxNonFocus" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/CheckBoxNonFocus" NineGrid="4,4,4,4"/>

  <Image Name="CheckBoxChecked" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/CheckBoxChecked" NineGrid="4,4,4,4"/>

  <Image Name="CheckBoxCheckedFocus" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/CheckBoxCheckedFocus" NineGrid="4,4,4,4"/>

  <Image Name="ContainerImage" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/Container" NineGrid="40,40,40,40"/>

  <Image Name="ButtonFocusImage" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/ButtonFocus" NineGrid="4,4,4,4"/>

  <Image Name="ButtonNonFocusImage" Source="resx://RealEstateSearcher/RealEstateSearcher.Resources/ButtonNonFocus" NineGrid="4,4,4,4"/>

</Mcml>

 

Finally, here is the code for MultiChoiceItem, which is used by the MultiSelect and checkbox.

 

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.MediaCenter.UI;

namespace RealEstateSearcher.Code

{

    /// <summary>

    /// Handles items used in a multi choice

    /// </summary>

    public class MultiChoiceItem : ModelItem

    {

        private bool _isSelected;

        private string _title;

        /// <summary>

        /// True if this choice is selected

        /// </summary>

        public bool IsSelected

        {

            get

            {

                return _isSelected;

            }

            set

            {

                if (value != _isSelected)

                {

                    _isSelected = value;

                    FirePropertyChanged("IsSelected");

                }

            }

        }

        /// <summary>

        /// The description of the choice

        /// </summary>

        public string Title

        {

            get

            {

                return _title;

            }

            set

            {

                if (value != _title)

                {

                    _title = value;

                    FirePropertyChanged("Title");

                }

            }

        }

    }

}