Monday, February 26, 2007

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

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.

Tuesday, February 13, 2007

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...

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.

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.

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

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

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).

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.

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.

Thursday, February 1, 2007

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

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.

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.

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...

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 :)

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.

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 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...

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 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&gt - 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.