Front End and Back End Synchronization in MCML

One of the issues that has been hardest for me to learn with developing media center applications as been the linking of front end items in the MCML layer with data that I have in c# on the back end. For a long time I struggled with binding values from the code in to front end, and making method calls from the front end in to the back end. I suspect that the reason I did this was because that is how it is shown in the Media Center SDK and documentation, so I thought it was the only way.

It turns out that the SDK is in fact showing the most complicated use case. There is a much easier way of linking the front end and the back end, that is so simple compared to the rest of MCML development that it’s almost non-intuitive. The technique is to create a UI item in your C# code, and then refer to that item on the front end. You don’t have two items, one front end and one back end. Instead you simply have one item that is referenced in both layers. That means that when you make a change to the value of the item in your C# code, the change is instantly reflected in the UI, and when you make a change to the value of the item in the UI, the C# code can reference that value instantly. Because it is the same physical item in memory.You can do this with any item that is a ModelItem. This includes Choice, BooleanChoice, Command, InvokeCommand, NavigateCommand, EditableText, ListDataSet, RangedValue, ByteRangedValue, IntRangedValue, Timer, PropertySet, and of course anything which you construct yourself which implements ModelItem. That covers a fair bit of the things you may wish to put on the page in Media Center.

One issue that I have found is that you simply declare a public object in your class, you can’t access it in the UI. If you expose the same object via an accessor, it works fine. I don’t know why, but sticking to that rule works fine for me. Here’s an example of some of them in action;

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.MediaCenter.UI;

namespace TunerFreeMCE
{
    public class PreferencesUI :ModelItem
    {
        private BooleanChoice _getBBC;
        private Choice _frequency;
        private EditableText _goUSCommand;
        private Image _twitLogo;
        private bool _twitButton1Visbility = true;
        private string _twitText;

        public PreferencesUI()
        {
            _getBBC = new BooleanChoice(this.Owner,"Get BBC");
            _frequency = new Choice(this.Owner, "Cache Frequency");
            _goUSCommand = new EditableText(this.Owner, "US VPN Command");
            ArrayListDataSet frequencyList = new ArrayListDataSet();
            frequencyList.Add("1 hour");
            frequencyList.Add("2 hours");
            frequencyList.Add("4 hours");
            frequencyList.Add("12 hours");
            frequencyList.Add("24 hours");
            _frequency.Options = frequencyList;
                _frequency.ChosenIndex = 0;
            _twitLogo = new Image("C:/Program Files/MillieSoft/TunerFreeMCE/Images/twitter_logo.png");
        }

        public BooleanChoice GetBBCValue
        {
            get
            {
                return _getBBC;
            }
            set
            {
                _getBBC = value;
            }

        }

        public Choice GetFrequency
        {
            get
            {
                return _frequency;

            }
            set
            {
                _frequency = value;
            }
        }

        public EditableText USCommand
        {
            get
            {
                return _goUSCommand;

            }
            set
            {
                _goUSCommand = value;
            }
        }

        public bool TwitButton1Visibility
        {
            set
            {
                _twitButton1Visbility = value;
                FirePropertyChanged("TwitButton1Visibility");
            }
            get
            {
                return _twitButton1Visbility;
            }
        }

        public string TwitText
        {
            get { return _twitDialog; }
            set
            {
                if (value != _twitText)
                {
                    _twitText = value;
                    FirePropertyChanged("TwitDialog");
                }
            }
        }

        public Image TwitterLogo
        {
            get
            {
                return _twitLogo;
            }
        }

    }
}

And here’s the corresponding MCML. The standard sample buttons and spinners are ommited – you can get those from the SDK very easily;

<Mcml xmlns="http://schemas.microsoft.com/2006/mcml"
xmlns:cor="assembly://MSCorLib/System"
xmlns:a="assembly://TunerFreeMCE/TunerFreeMCE"
xmlns:addin="assembly://Microsoft.MediaCenter/Microsoft.MediaCenter.Hosting"
xmlns:mc="assembly://Microsoft.MediaCenter/Microsoft.MediaCenter"
xmlns:me="Me">

<UI Name="Preferences">

    <Locals>
      <a:PreferencesUI Name="Preferences"/>
    </Locals>
    <Rules>
      <Binding Source="[Preferences.TwitButton1Visibility]" Target="[SetTwitterUsername.Visible]"/>

    </Rules>
    <Content>
      <Panel Layout="Dock">
        <Children>
          <Panel Layout="Dock" MaximumSize="0,80">

            <LayoutInput>
              <DockLayoutInput Position="Top" Alignment="Near"/>
            </LayoutInput>
            <Children>
              <Panel Layout="VerticalFlow">
                <Children>
                  <!-- Title text. -->
                  <Text Name="Banner" Content="[Preferences.TwitText]" Color="White"
										  Font="Sergio UI,45" Margins="10,0,0,0">
                  </Text>
                </Children>
              </Panel>
            </Children>
          </Panel>
                  <Panel  Margins="20,0,0,0">
                    <Layout>
                      <FlowLayout Orientation="Vertical" Spacing="10,10" StripAlignment="Near"/>
                    </Layout> 

                    <Children>
                          <Panel Layout="VerticalFlow">
                            <Children>

                              <Graphic Content="[Preferences.TwitterLogo]" Name="TwitterLogo" Margins="0,2,0,0">

                              <me:SimpleButton Name="SetTwitterUsername" EnormoList="[EnormoList]">
                                <Command>
                                  <InvokeCommand Description="Set Twitter Username" Target="[Preferences.launchTwitterURL]"/>
                                </Command>
                              </me:SimpleButton>

                              <me:SimpleCheckBox EnormoList="[EnormoList]">
                                <Model>
                                  <BooleanChoice BooleanChoice="[Preferences.GetBBCValue]"/>
                                </Model>
                              </me:SimpleCheckBox>

                              <me:SimpleSpinner EnormoList="[EnormoList]">
                                <Model>
                                  <Choice Choice="[Preferences.GetFrequency]"/>
                                </Model>
                              </me:SimpleSpinner>

                              <me:SimpleEditBox EnormoList="[EnormoList]">
                                <EditableText>
                                  <EditableText EditableText="[Preferences.USCommand]"/>
                                </EditableText>
                              </me:SimpleEditBox>

                            </Children>
                          </Panel>

                    </Children>
                  </Panel>
        </Children>
      </Panel>
    </Content>

  </UI>

As you can see, the BooleanChoice is rendered as a checkbox on the page, the Choice as a spinner, the EditableText as a text box, the Image as a Graphic, the boolean is used to change the visibility of an item, and the string as display text. All of these items are defined in code and then referred to in the page, sometimes as a direct reference to the item, and sometimes as a property of another item.

This can be a complex lesson to get to grips with, but once you realize how this works, MCML programming becomes a whole lot easier.

Tags: , ,

Leave a Reply