Monday, February 26, 2007

New Blog at The Digital Lifestyle

Ian Dixon - the man behind The Media Center Show podcasts - has recruited me to be (one of?) the developer(s) writing for the Media Center Development blog at TheDigitalLifestyle.com.

Because the site is a little easier to use in terms of spell-checking and pasting code, I'm probably going to be spending a little more time at the new blog. To start with I'll mainly be re-posting nicely-edited versions of the posts I've already put here. New content won't take long though guys.

Check it out at http://thedigitallifestyle.com/cs/blogs/developer/default.aspx

Monday, February 19, 2007

MCMLookalike Initial Release

The first release of MCMLookalike is done. I threw the project and installer together in around about 45 minues (not counting the 'controls.mcml' file), so I hope there are no GLARING errors in the code.

If you are an MCML developer, take a look. It's a basic program using a couple of simple pre-defined controls. It also includes a template installer you can use to distribute your program.

http://www.sourceforge.net/projects/mcmlookalike

Tuesday, February 13, 2007

Installing Your Program - Part 2 - Installing Your Files

Step 2 of the install process is nice and easy - no command-prompt needed :)

Create a new project (add it to the existing solution) in Visual Studio. Under 'Other Projects', you'll find "Setup and Deployment". This will allow you to create an installer.

Give your program a name like <program name>Setup - try to steer clear of generic names like 'setup', simply because it's very easy to get your 'setup.msi' confused with hundreds of others with exactly the same name.

Now your new project should appear in the Solution Explorer. Click it, and go to the 'View' menu. Under 'View', you should now have the 'Editor' submenu. This allows you to choose to edit the various parts of your installation - the files, registry settings etc.

Choose 'File System', if it isn't selected already.

The first entry will read 'File System on Target Machine'. Right-click this line and a popup menu will appear. Choose 'Add Special Folder|Global Assembly Cache Folder' to add the GAC to your installer.

Right click on the new folder that will appear and choose 'Add|Project Output...' from the popup menu. You can then 'Primary Output' from the list of different types of file you can include from your project.

This will add your .NET classes into the Global Assembly Cache, as well as get a reference to a number of extra DLL's and modules that your application will require. If you check the solution explorer, you'll notice that Microsoft.MediaCenter.dll and a couple of it's friends will have appeared.

We don't need to install these, although they ARE required for your program to work correctly. To avoid installing these (which would be illegal), we right click on the files and choose 'Exclude'.

There! Your .NET files are now installing. The next thing we need to do is tell Media Center where our program is, what it does and what it's called. That's covered in the next post...

Installing Your Program - Part 1 - Signing Your Assembly.

This is the first part of my little review on writing an installer to get your MCML program into Media Center.

The code part of your Media Center program (usually written in C#) is installed into the Global Assembly Cache (GAC) of Windows. The GAC is used to store .NET assemblies that are shared across multiple programs. Your basic Windows forms classes etc. all live in the GAC.

Before any program can be added to the cache, it must be strongly named. A strongly named assembly has a public and private key associated with it, to ensure that it is actually the original class and not a modified or doctored version.

To generate this key, you will need to use the 'SN' command that ships with Visual Studio. You will find it in <Visual Studio Install Directory>/SDK/v2.0/BIN

Use 'cmd' (the command-line interpreter) or even better, open the command prompt from the start menu, under 'Programs|Visual Studio 2005' so you won't need to bother with your path information.

Type 'sn -k <filename>.snk' to generate a new key file.

Then in Visual Studio, right click on your project in the project view and choose 'Properties' from the drop-down menu that will appear. Under 'signing' you will have the option of choosing a key file. Choose the one you created with the SN utility, and rebuild your project.

There! You have a signed assembly, ready for installation into the GAC.

Monday, February 12, 2007

Yougle Now Installing

My next blog entry will be on writing installers.

Just to prove that I'm not COMPLETELY full of it, here's an image from my current MCML project.



Of course there's a lot of work to be done, the interface has to be prettied up a lot - but at least you know I'm not just making all of this up :)

Thinking and Transferring Data in MCML

OK, I understood the basics of this one when I started, but just to help those newbies out (for instance, there have been a few messages like this on the MediaCenterSandbox), I'll go over the code/view seperation that you find in MCML.

There are two major components of any MCML application. These are the user interface elements (the .MCML files) and the code (the C# program).

In most ocmmon programming models, your code will directly reference the controls For example, you will set the text on the button called 'Button1' to say 'Hello' with the command "Button1.Caption='Hello';" or through messages like "SetDlgItemText(IDC_BUTTON1,'Hello');".

In MCML, the user interface and your code are kept seperate. You never directly reference any controls or user interface elements from your code.

Instead, MCML has access to the properties of your objects. So basically you choose what properties you want to show on your interface and hand them to your MCML page as properties.

Your MCML page is where your object is created. You can then access all of the public properties of the object and use them in your MCML file.


An example of passing a value from C# to MCML...


So in C#, you have a class like this

public class MyObject
{
//The underlying data

protected string _MyStringValue;

//The property to read in MCML
public String MyStringValue
{
get
{
return _MyStringValue;
}
}
}


And then if you want an MCML text object that uses the value...


<UI Name="MyObject">

<Content>
<Text Name="MyData" Color="White"/>
</Content>

<Locals>
<a:MyStringValue Name="Val"/>
</Locals>
<Rules>
<Binding Source="[Val.MyStringValue]" Target=[MyData.Content]"/>
</Rules>
</UI>


This assumes you are importing your C#/.NET assembly with the namespace 'a' (this is the default when you create an MCML project in Visual Studio, so you shouldn't have to add this line to the first tag of your document).

Wednesday, February 7, 2007

Navigating - and Another MCMLPad Warning

There's another minor bug/issue in MCMLPad - something you should be aware of once you start doing more advanced development.

To navigste from 'page' to 'page' (eg. between UI's) you can use the <Navigate> action within any Rule.

The only required member of this tag is URI - the address to the next page. Most frequently, this will be a link to an MCML file that you have enclosed in a resource (usually the same DLL that contains your .NET application).

You can also pass objects in this Navigate tag. Since Navigate opens another UI as the main interface, you pass objects to this new UI exactly the same way that you do between UI's in a single interface - by passing them as properties.

So, for example, you can create a property on the base-UI in 'Page2.mcml', and set it with the Navigate tag in 'Page1.mcml'. This is how you can continue to pass information between pages and propagate information through your entire application.

ONE WORD OF WARNING: MCMPad has a small glitch (I hesistate to call it a 'bug', but it IS annoying) where pressing F5 to refresh the page will NOT work correctly for any page that has been passed a property. The property will not be re-sent, which means that any strings will be reset to empty and any objects will be set to 'null', which will normally mean that MCMLPad will close with an exception.

Monday, February 5, 2007

Input Handling

Welcome back for another blog entry.

Today we have a quick tip on input handling (and playing with .NET variables) in your MCML interfaces.

Every object in your MCML interface has an Input object associated with it. This is what allows you to find out if the item has mouse or keyboard focus. It ALSO lets you control how that focus works.

To tell if the mouse is hovering over an object, you need to check the [Input.MouseFocus] property. Since every object has it's own 'Input' object, the properties of Input will always refer to this object only (or it's children, if you are using DeepFocus).

<UI Name = "Selectable">
  <Rules>
    <Condition Target="[Input.MouseFocus] Value="true"\>
      <Actions>
        <Set Target=[TextObject.Color]" Value="Red"\>
      </Actions>
    </Condition>
  <\Rules>
  <Content>
    <Text Content="Push Me" Color="White" Name="TextObject"\>
  <\Content>
<\UI>

The trick to using their advanced properties is simple, but can throw you if you are new to MCML. Objects like Input are NOT actually XML tags, despite the fact that in the documentation they are shown as XML. Instead, they are .NET objects, and you set the properties of the Input object through the Default tag of your Rules object.

For example, we can mark a panel as being able to receive focus with the KeyInteractive property.

<UI Name = "Selectable>
  <Rules>
    <Default Target="[Input. KeyInteractive] Value="true"\>
  <\Rules>
  <Content>
    <Text Content="Push Me"\>
  <\Content>
<\UI>

This creates a text object that you can navigate to with you remote/keyboard.

One more hint - MCML's default is that a mouse-focus event always fired off a matching key-focus event. Sometimes, this just isn't right.

For example, in the AreaBar (the pivot bar, or the blue list of sorting options that appears in most genuine Media Center screens), you find that when you navigate by key-press or remote, you automatically select the next area/option that you navigate to.

When using a MOUSE, you only HIGHLIGHT it. You have to click the mouse button to select the option.

However, the default behaviour for Media Center is to automatically set 'KeyFocus' to true every time 'MouseFocus' is. This sort of thing is great for regular buttons, but isn't effective for this particular control.

So to emulate this behavior, you need to use

<Rules>
  <Default Target="[Input. KeyFocusOnMouseEnter] Value="false"\>
<\Rules>

This prevents [Input.KeyFocus] from being true every time that [Input.MouseFocus] is.

Thursday, February 1, 2007

MCMLPad, and a Better Blog

Three quick notes for todays post.

1) MCMLPad (the program used to test your MCML interfaces) does NOT scale correctly. I'm sure you'll find a reason for this in the Microsoft Knowledgebase, filed somewhere under 'flimsy justifications', but in the mean time be aware that if you are testing something to ensure it size and layout is correct, launch MCMLPad from Media Center instead

When started from Media Center, MCMLPad will function correctly and scale appropriately.

I blew almost two hours trying to figure out how to scale the darn interface properly with ScaleLayouts, and wondering why none of the MS examples included the basic functions to scale the interface - only to find out that it's an odd quirk with MCMLPad.

Thought I may save you guys the time :)

2) My next tutorial was going to be on what I called the 'CategoryBar', the blue bar that allows you to choose the category/sort order in most Media Center windows. However, someone beat me to it (and quite franky, is much better than I am anyway). Check out http://mobilewares.spaces.live.com/ to see a master at work! He also has an excellent tutorial in creating 'Gel Buttons', the new version (found in Now Playing) of the old Media Center 2005 style interface buttons.

3) I've opened a new SourceForge project, called MCMLookalike (www.sourceforge.net/mcmlookalike), to create open source, shared libraries for MCML development. Feel free to use them and contribute to the project - the first files should be uploaded this afternoon.

Wednesday, January 31, 2007

Tips & Tricks: 'Global' Variables

A quick word for the wise when it comes to MCML and your variables.

As much as you would like every UI to be it's own completely autonomous control, there are times when you need real feedback from your UI's.

This can actually be quite a problem, since a UI can not talk to it's parent.

So what is the trick? It's actually not too difficult, but for the newbie it can be very confusing.

We have already introduced properties, allowing you to set the attributes of the UI's you are creating. As well as properties, we have locals. These are in a very similar form to properties, with the only real difference being that you can't tell a UI what it's locals should be.

The trick is to take one of your local variables and basically just 'pass it on' as properties to all other objects that need access to it.

BUT - and here's the trick - you need to be aware of what TYPE of property you are using. This is because the variables work differently depending on what type you use.

If you use an object from the cor: namespace (such as cor:String, cor:Int32, cor:Boolean etc.) then you have created a simple type, like 'int' or 'long' in C. If you pass simple objects to a UI, it gets it's own new copy of the variable, meaning that if you change the value in any of your sub-items, the change will only effect THAT ITEM.

However, if you use something more complicated, a CLASS like EditableText for instance, every UI that is sent it as a property gets a reference to the object. This means that when you change a value in ANY of the UI's you have passed it to, it will be changed for ALL UI's.

<UI Name="MainUI">

  <Locals>
    <cor:String Name="Brand" cor:string="My Brand">
    <EditableText Name="Area" EditableText="None">
  </Locals>

  <Content>
    <Panel Layout="VerticalFlow">
      <Children>
        <Text Name="BrandName" Color="White" Font="Tahoma,20"/>
        <Text Name="AreaName" Color="White" Font="Tahoma,20"/>
        <me:BrandedOption BrandVar="[Brand]" AreaName="Option #1" BrandName="ACME" AreaVar="[Area]"/>
        <me:BrandedOption BrandVar="[Brand]" AreaName="Option #2" BrandName="Someone Else" AreaVar="[Area]"/>
      </Children>
    </Panel>
  </Content>

  <Rules>
    <Binding Source="Brand" Target="BrandName.Content">
    <Binding Source="Area" Target="AreaName.Content">
  </Rules>

</UI>

<UI Name="BrandedOption">

  <Properties>
    <cor:String Name="BrandVar" cor:string="$Required">
    <cor:String Name="BrandName" cor:string="$Required">
    <EditableText Name="AreaVar" EditableText="$Required">
    <cor:String Name="AreaName" cor:string="$Required">

  </Properties>

  <Content>
    <Panel Layout="HorizontalFlow">
      <Children>
        <Text Name="ButtonArea" Color="Red" Font="Arial,20" Content="[AreaName]"/>
        <Text Name="ButtonBrand" Color="Red" Font="Arial,20" Content="[BrandName]"/>
      </Children>
    </Panel>
  </Content>

  <Rules>
    <Condition Source="[Input.MouseFocus]" SourceValue="true">
      <Actions>
        <Set Target="[BrandVar]" Value="[BrandName]">
        <Set Target="[AreaVar]" Value="[AreaName]">
      </Actions>
    </Condition>
  </Rules>

</UI>


I haven't actually TESTED this UI (although I do something similar in my existing MCML) but that will give you the basic outline.

What we have is an interface that has two text boxes in white, giving you the current brand name setting, and the current area name setting. These are constantly updated with the rule we have specified, which makes sure the value of 'Area' and 'Brand' are copied into the text controls whenever the values are updated.

There are also two buttons. Each button has two text elements, the brand and the area/type of a product (set with the AreaName and BrandName properties) and the button is also passed our global Brand and Area variables through the AreaVal and BrandVal.

In the buttons, we have a rule that says that whenever the object is given mouse focus (Input.MouseFocus = true) then we are to set the AreaVal and BrandVal properties to AreaName and BrandName (the names displayed on the button).

What you should find when you do this is that when you roll over a button, the AREA will change, but the BRAND will not. This is because of the rules I explained earlier.

So now you know how to share a variable through your entire UI. This will come in handy in the next project discussed.

Tuesday, January 30, 2007

Looking Like Media Center: Background Text

OK, we now have the tools in hand to create our first UI element - the text that appears in the background of Media Center interfaces (check in the top right corner of almost any Media Center window).

It's a fairly simple beast really - we simply need a text control that gradually fades out vertically.

But we are going to implement this as a reusable control. So put your MCML hats on, and let's dive in.

<UI Name="BackgroundText">
</UI>


That's kind of obvious really - we have defined our control.

Like our previous example, we are going to need to be able to change the text that appears in the control. We will use a property called 'Label'.

...
  <Properties>
    <cor:String Name="Label" cor:String="$Required">
  </Properties>
...


Now we create the control we need...

...
  <Content>
    <Text Name="TextLabel" Color="White" Font="Arial,40"/>
  </Content>
...


And we set up a binding between the property Label and the text control TextLabel.

...
  <Rules>
    <Binding Source="[Label]" Target="TextLabel.Content"/>
  </Rules>
...


OK, that gets us text...but it's bright white! That's not really of any use to us yet. So first, we need to set the alpha property of the text. This chooses how transparent it is going to be. We need the background blue to show through into our interface, so we need something around 25% transparent. So an alpha value of 0.75 (Alpha is a measurement of how VISIBLE an object is, so it's the inverse of the transparency of an object) will do nicely.

    <Text Name="TextLabel" Color="White" Font="Arial,40" Alpha="0.75"/>

Well, it's now transparent, but we have no fade. The last step in this process is to create a CLIP object, which will allow us to make gradient fades around the edges of a defined rectangle.

Clip objects contain all of the objects they will effect, so we need to change the content tag to contain the following...

...
  <Content>
    <Clip Orientation="Vertical" MaximumSize="300,60" FadeSize="26" NearOffset="-40">
      <Children>
        <Text Name="TextLabel" Color="White" Font="Arial,40"/>
      </Children>
    </Clip>
  </Content>
...


The key to the fading is the 'FadeSize', 'Orientation' and 'NearOffset' attributes of the Clip object.

Orientation determines the direction of the fade (eg. since we want the text to fade downwards, Vertical is the obvious solution).

Fadesize is the physical size of the gradient fade. A fadesize of 26 like we have above will make all objects start fading once they are within 26 pixes of the edge of the box.

NearOffset (and FarOffset) adjust the starting places of the gradient fades. In this case, we are moving the NearOffset WAY back. This is so that the TOP of our next does not become faded, but the BOTTOM will be, because we have left FarOffset at it's normal level.

There you have it. A reusable control to start you on your way. Of course, we still need to tweak the font to match the one used in Media Center, but I'll leave that up to you. And when you DO figure it out, could you tell me what it is? I can't find the bugger :)

<UI Name="BackgroundText">
  <Properties>
    <cor:String Name="Label" cor:String="$Required">
  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="TextLabel.Content"/>
  </Rules>

  <Content>
    <Clip Orientation="Vertical" MaximumSize="300,60" FadeSize="26" NearOffset="-40">
      <Children>
        <Text Name="TextLabel" Color="White" Font="Arial,40"/>
      </Children>
    </Clip>
  </Content>

</UI>

Monday, January 29, 2007

Turning UIs into Controls

As I mentioned last post, UI's contain not only content, but also can have their own properties and local variables. We are going to play with those now, to create a more flexible, reusable control.

This time we are creating a text object in a coloured box. We are starting with the code we were using in the last post :

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BooText>
      <me:BooText>
    </Panel>
  </Content>
</UI>

<UI Name="BooText">
  <Content>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
  </Content>
</UI>


So the first step is to add our coloured box. This is easy - it's done with a colorfill.

So 'BooText' changes to become...

<UI Name="BooText">
  <Content>
    <Colorfill Content="Red">
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
    </Colorfill>
  </Content>
</UI>


In the above code we have surrounded the text control with a filled red square.

But just saying 'Boo' is very, very boring. We can't expect to reuse a control like that. So now we need to add a property to our BooText UI. And while we are there, let's rename it to 'BGText'.

<UI Name="BGText">
  <Properties>
    <cor:String Name="Label" String="$Required"/>
  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="[MainText.Content]"/>
  </Rules>

  <Content>
    <Colorfill Content="Red">
      <Text Name="MainText" Font="Tahoma,30" Color="Blue"/>
    </Colorfill>
  </Content>
</UI>


Yes, this may need a little bit of explaining.

The first thing we did was declare a new property for this UI. In this case, it's a String (from the cor namespace) named 'Label'. We have set it to the reserved word '$Required' instead of giving it a value (eg. cor:String="My Default Value") which means that the UI that creates this object MUST specify the label.

The label can be assigned either as an attribute (eg. <me:BGText Label="My Label"> or as a tag (eg. <me:BGText><Label>My Label</Label></me:BGText>

In the next part of our UI, we defined a rule. This controls how the control actually responds at runtime. In this case, we have created a binding. We have bound the property called 'Label' to the Content property of the control name MainText. This means that when we pass a value to the Label property of this UI, it will automatically be copied over into the text control named 'MainText'.

Then in our content section, we have given the text element a name (MainText) and removed the Content section, since we will now be giving it content through the Label property.

Last step - change the main UI to reflect our changes.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BGText Label="Text #1">
      <me:BGText Label="Text #2">
    </Panel>
  </Content>
</UI>


So we now have two text boxes, one saying "Text #1" and one saying "Text #2", with coloured backgrounds.

Of course, you can play a lot more. You can give the control more properties. For instance, properties to adjust the colour of the text, the colour of the background, the font, etc. Just remember that instead of using the name of the colour (eg. "White") you use the name of the property, in square brackets(eg. "[BackgroundColour]")

<UI Name="BGText">
  <Properties>
    <cor:String Name="Label" String="$Required"/>
    <Color Name="TextColour" Color="White"/>

  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="[MainText.Content]"/>
  </Rules>

  <Content>
    <Colorfill Content="Red">
      <Text Name="MainText" Font="Tahoma,30" Color="[TextColour]"/>
    </Colorfill>
  </Content>
</UI>

What is this UI thing anyway?

OK - Let's talk about UI's.

UI is (of course) short for User Interface. All of your visible controls (text, colorfills, panels, graphics etc.) must be within the 'contents' tag of a UI.

But they are more than just a once-off tag.

For those familliar with .NET programming (and from now on in this blog, I'm going to assume you know the basics of object oriented programming, either C++, Java, C# or J# will do), a UI is also very much like a control class.

Each UI can have properties, local variables, rules of behaviour and it's own appearance. You can use UI's and name them to define a set of reusable controls.

Before we can use a UI, we need to make sure there is a line at the top of our MCML file, one that creates a namespace so we can play with our own UI controls. If you have created your MCML from the wizard in Visual Studio, you may already have it. For those who are hand-writing it, make sure your first tag looks like this...

<Mcml xmlns="http://schemas.microsoft.com/2006/mcml"
xmlns:cor="assembly://MsCorLib/System"
xmlns:me="Me">


OK - so now every UI we create in this document will be in the namespace called 'me' (which is what that whole xmlns:me thing is about.

Now, the first UI is the MAIN UI. This is the one that will automatically be drawn by Media Center.

We will keep our first example very simple. We want two lines of text, both saying 'Boo!' in blue.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
    </Panel>
  </Content>
</UI>


Or, we could create a new UI, making a reusable control for our text item.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BooText>
      <me:BooText>
    </Panel>
  </Content>
</UI>

<UI Name="BooText">
  <Content>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
  </Content>
</UI>


OK, we didn't save much space this time. But check the next post for how this starts to become useful.

Project 1 - A Basic MCML File

This is the first part of my project. Like all my Media Center interfaces, the new version of Yougle is going to have the same look and feel (or as close as I can get to it, anyway) as the Media Center interface.

But I'm just starting out here, so let's get the basics covered.

Step 1: Make sure Visual Studio 2005 (Express or Pro) is installed. They aren't required for a basic application, but chances are you'll want to write some code to work behind the UI eventually - that, and the fact that Intellisense works for your MCML file in Visual Studio is just plain invaluable.

Step 2: Download and Install the Windows Media Center 5.0 SDK from http://www.microsoft.com/downloads/details.aspx?familyid=a43ea0b7-b85f-4612-aa08-3bf128c5873e&displaylang=en

Step 4: Create a new project in Visual Studio. Once the SDK is installed, you will have a new template under 'Media Center Applications', called 'Windows Media Center Presentation Layer Application'. This will set up a project so you can get started quickly and easily.

Step 5: Now, it's time to write some MCML code. MCML is an XML based language, so all the usual rules to tagging apply. You'll have an MCML application already generated with colour-changing text and a bouncy smiley button. But for now, Let's kill that off and learn a couple of new tags...

<mcml> - Just like the 'html' tag in web pages, this tag is the first one that should appear in any MCML file, after the schema information.

<ui> - This defines a User Interface. These are also used to define new types of reusable control. We will explore this a lot more later. Right now, we just need to get us a working page, so simply know that everything inside a UI tag is part of your user interface.

<text> - This, quite obviously, displays some text.

So, let's get some code in.

<mcml> <ui name="HelloWorld">
<content>
<text content="Hello World" color="White">
</content>
</ui>
</mcml>

There ya' go. A working MCML file, which should give you a 'Hello World' in pretty white, sitting in the middle of the screen.

Don't you feel special?

Next up: Using UI's

Welcome

This blog will hopefully contain a record of all of the stages I've gone through in developing a Media Center application.

If you want any help with an MCML app, feel free to browse the information here - there may be useful source code for you to 'borrow'.

And of course if you see me saying something completely stupid, jump right in and correct me.