SideShow notifications and events

Fri, December 29, 2006, 08:44 PM under Windows | Vista | SideShow
When I introduced the SideShow gadget fundamentals, I listed 3 types of communication between the gadget running on the PC and the SideShow-compatible device. You know how to design your SCF content and then download it via the managed API. Here I will introduce notifications and events.

Notification
Sending a notification down to the device takes one line of code, given that you already have a ScfSideShowGadget reference as described before:
Icon ico = new Icon(@"C:\Users\Public\Pictures\SideShow\SSnotification.ico");
g.ShowNotification(
100, // unique content id
"some caption", // caption
"some message", // body
ico, // icon to appear on the far right of the body
TimeSpan.FromSecondss(30)); // timeout interval
Executing the above will result in the behaviour captured below on the SideShow simulator:

The notification will time out after the timeout period specified or the user can manually dismiss it with the ENTER button or, finally, you can programmatically dismiss a notification by its id e.g. g.RevokeNotification(100); or a more brutal approach g.RevokeAllNotifications;

Events
There are 9 events that you can handle programmatically on the PC-side while the user performs actions. The following code shows hooking up to them
g.AllDevicesRemoved += new EventHandler(g_AllDevicesRemoved);
g.ContentMissing += new EventHandler <ContentMissingEventArgs> (g_ContentMissing);
g.ContentNavigate += new EventHandler <ContentNavigateEventArgs> (g_ContentNavigate);
g.ContextMenuSelect += new EventHandler <ContextMenuSelectEventArgs> (g_ContextMenuSelect);
g.DeviceAdded += new EventHandler <DeviceCapabilityEventArgs> (g_DeviceAdded);
g.DeviceRemoved += new EventHandler <DeviceCapabilityEventArgs> (g_DeviceRemoved);
g.GadgetEnter += new EventHandler(g_GadgetEnter);
g.GadgetExit += new EventHandler(g_GadgetExit);
g.MenuSelect += new EventHandler <MenuSelectEventArgs>(g_MenuSelect);
- GadgetEnter, GadgetExit when the user navigates from the glance data page (id=0) to the SCF pages and back.
- DeviceAdded, DeviceRemoved, AllDevicesRemoved when SideShow-compatible device connect or disconnect from this gadget.
- MenuSelect, ContextMenuSelect when the user selects one of your menus or opens your contextmenus.
- ContentNavigate every time the user traverses from one SCF page to another.
- ContentMissing if a user action results in a request for a content id that is not on the device.

The event handler method signatures for these follow the standard .NET pattern of having two parameters. The first being the sender object and the second being a type that inherits from EventArgs. The following class diagram shows the EventArgs classes with their members so you can get an idea of the information you receive with each event mentioned above:


Stay tuned on this blog for more on SideShow gadget development in the new year ;-)

5 things you didn’t know about me

Thu, December 28, 2006, 03:10 PM under Random
MarkJo (whose accent is definitely funnier than mine despite what he claims) has tagged me in this meme... and as my regular readers will know I don’t do memes but, hey, there is always the first time I guess... :-)

1. Before deciding to study computer science in the UK (also known as “before my mum insisted I study”) I was a magician in Greece and actually appeared live on national Greek television. I still have the business cards!

2. When I am behind the wheel I just can’t help speeding. I have 6 points on my license (gained with my Punto GT Turbo); with my brand new Golf GTI 2.0 (200bhp) I am bound to increase them. Problem is that the more points you get the more chances of losing the license and that would most definitely mean losing my job. Not joking, this is a dead serious concern of mine and probably what will force me into working for myself full time from home.

3. I love travelling and have been almost everywhere. If I could live anywhere in the world it would be Australia where I’ve spent 3 unforgettable weeks. Only issue is convincing the wife who prefers Europe as our residence...

4. While competitive at most things I do, the one I always brag about is chess. If you think you have what it takes, challenge me!

5. The last thing you probably don’t know about me is that I have switched the search engine of this blog to LIVE. Check out the cool interface on the left... type “NETMF” in the box and hit enter, you know you want to :-)

Doh... I almost hit “submit”, but this is a meme so I have to tag 5 other bloggers. Let’s see if these guys are listening and want to play:
Angelos , Eileen , Mike , Peter , Scott.

New NETMF web pages

Thu, December 28, 2006, 08:05 AM under MobileAndEmbedded
There is a NETMF book on the horizon and check out its very own book website (thanks Mike for the heads-up).

NETMF also gains its own NETMF MSDN area :-)

More on device development on Vista

Tue, December 26, 2006, 06:07 PM under MobileAndEmbedded
Remember the problem I got when trying to deploy to a real device from VS2005 on Vista? As that blog entry says, the solution was to run VS elevated once and that rectified the issue.

On an internal list I noticed someone else had a device issue on Vista this time with Platform Builder 6.0 and their error apparently was:
PB Debugger Warning: Debugger service map is set to none. If your image has debugging support it may not boot properly

...guess what the solution was again? Correct, run VS elevated once.

The other day at an offsite I did a very short intro to Windows Mobile development so I wanted to show first a small desktop app, then the same code in a device project connecting to a device and then connecting to an emulator. I prepared the machine before the short presentation by running VS normally for the desktop project and then running another instance elevated for the device project. I also wanted to save time by launching the emulator ready to use, so I did that from the VS menu and the first instance of VS that I came across was the desktop project. Can you spot the mistake I made?

When later in the presentation I tried to connect from the device project to the emulator I was treated to this:
---------------------------
Device Emulator
---------------------------
Error: The current VMID is in use. Wait for the other application to exit.
---------------------------
OK
---------------------------
Cryptic or what? The solution of course was to shut down the emulator and this time launch it from the elevated VS instance.

The moral of the story: You cannot have an elevated VS instance talking to a non-elevated emulator.

NETCF goodness in XNA and hopefully vice versa

Fri, December 22, 2006, 05:00 PM under MobileAndEmbedded
I hope by now everyone has heard about the XNA Framework, a set of managed code libraries for writing games on the Xbox and the PC.

Not everyone will know that the engine in XNA is based on the CLR of the .NET Compact Framework (I first heard about it here). What this could mean to device developers is that the next version of the NETCF has even more performance improvements (wouldn’t you back port any perf changes you made ;-)).

Existing NETCF application developers are prime candidates for becoming good XNA game developers (assuming you are not graphically challenged like me!). For those of you that haven’t dabbled with the NETCF before, learn how to write XNA code that performs well and read these 2 fresh posts by Chris To of the NETCF team: Part 1, Part 2.

Writing managed control panel items

Fri, December 22, 2006, 09:36 AM under Windows | Vista
In the past, if you had to develop control panel items you would start thinking about .cpl files. With Windows Vista, there seems to be a tendency to take advantage of the new ability to create them in separate executables! Those of you that know me long enough can see where I am going with this... it means that we can develop these in managed code now :-)

I will assume that you have a scenario for actually integrating with the control panel and I will just share the mechanics. Create your managed Windows Forms application and give it whatever UI you want. You actually don’t have to do anything special in the project. In fact, you could even reuse your existing main application and just use a command line option for when it gets launched from the control panel.

So once you have the exe, how do you integrate it with the control panel? The answer is by adding some registry entries.
1. Buy yourself a GUID. In all my screenshots below, replace my guid ({ABB4AAE7-3D21-45f7-AA1C-F470FAB07B89}) for the one you have.

2. Create a key with this GUID under HKLM at the path shown in the screenshot below (hint: look at the statusbar):

3. Do the same this time under HKCR at the path shown in the screenshot below:

4. Look at the values for the screenshot above. For the first 3 values you can enter anything you like. The last value points to a path and do not worry about that right now. The 4th value (System.ControlPanel.Category) tells the system under which category you want a link to your executable to appear in. I’ve chosen 7 and 9 which are the “User Accounts” and “Ease of Access” categories. The following screenshot shows the effect of the few registry entries we created. Note how values from above match the UI (inc. tooltip).

You can find your link under both aforementioned categories and it is immediately searchable as well.

5. If you click on your item, explorer.exe will show an error box “Application not found”. Close the control panel and let’s go make one more registry entry. Create 3 subkeys as shown in the following screenshot and note how the default value under Command specifies the path to the executable (you could have specified a command line argument if you wanted):

Launch the control panel again, and this time when clicking on your link, your application will open.

Also, remember the string we entered for the System.ApplicationName registry value? If you entered the same as me, you can now launch your application from the command line
control /name Daniel.MothPanelApplet

6. An optional additional step is to specify task links under your item. This is where the path to the file we mentioned above comes in. At the moment your System.Software.TasksFileUrl value points to an invalid path. Make it point to this file after you copy it to your machine. Close Control Panel and after reopening it, under “User Accounts”, you find a something like the following:

If you navigate to the “Ease of Access” category, you’ll find a slight variation as shown in the screenshot behind this link.

More Info
There is a lot more to check out including how to change the icon that appears in the control panel, what the numbers for the other categories are, how to launch other items from the command line, design guidelines, explanations on the XML file for tasks, creating cpl items, what else is new in Vista and a lot more. The following msdn links should cover that material for you:

Tour of UI

Quick intro similar to mine

UX guidelines for control panels

Comprehensive control panel overview

TVS_EX_AUTOHSCROLL

Tue, December 19, 2006, 10:39 AM under Windows | Vista
Open your windows explorer on Vista and click around the “Folders” section in the left (below your “Favorite Links”). Do you observe two things that were not there pre-Vista? That is right, the treeview has no horizontal scrollbar at the bottom and scrolling happens for you automatically as you select nodes that are not fully visible and as you mouse over around. Resize that area to be smaller if you are not observing this effect. Now do you notice the effect? Cool :)

It turns out that you can make any TreeView behave like that, if you want to. The clue for me was accidentally coming across the TVS_EX_AUTOHSCROLL constant.

<this took me longer than what it should>
I must admit that it took me a while to get this working. First when my simple mind encountered extended style it thought: “I know those and I know how to change them for managed controls”. So I overrode CreateParams and changed the ExStyle property but that had no effect. I then assumed that the reason it wasn’t working was because I had to send it the TVM_SETAUTOSCROLLINFO message so I played with that, messing with various values since the documentation gives no clue to sensible starters and then gave up when I was still not observing the results. BTW, spy++ wasn’t helping much since prolongued use caused the machine to freeze and rebooting added to my overall frustration. Eventually a virtual slap made me realise that I need to send a custom message for the extended treeview style (not window style). Digging around I found the TVM_SETEXTENDEDSTYLE message and tried sending that. Another round of trials and errors with no luck; only after opening commctrl.h I could work out what params to send and in what order. I knew the messages were reaching the TreeView as I started using my own TreeView and overriding DefWndProc with debug statements to make sure that the message wasn't been swallowed by the managed implementation. A complete red herring came out of nowhere questioning whether I was using v6 of comctl32.dll (of course I was, my commandlinkbutton etc worked fine, but to be positive, I manifested the assembly to make sure that was indeed the case). At this point, you can imagine that I was hacking at this API for quite a while, editing code and then running the project. At some point I got lazy and my test of whether it worked or not was: Does an hscrollbar appear in the treeview. Well it turns out that, at least for the System.Windows.Forms.TreeView, the documentation is wrong: the hscrollbar does not go away with this style!! Doh! God knows how many times I had this working and thought I hadn’t because of the visual false positive :-(
</this should it what than longer me took>

Anyway, once I started testing properly again, not only it worked but I also realised that you don’t really need to send auto scroll info since it has some sensible defaults. So the bare minimum to get the TreeView to automatically scroll horizontally based on node selected and mouse position, is the following:
NativeMethods.SendMessage(treeView1.Handle, NativeMethods.TVM_SETEXTENDEDSTYLE, 0, NativeMethods.TVS_EX_AUTOHSCROLL);

If you actually want to change the speed of auto scrolling combined with a scroll timeout, then you must do this:
NativeMethods.SendMessage(treeView1.Handle, NativeMethods.TVM_SETAUTOSCROLLINFO, 30, 10); 

And if you want to get rid of the hscrollbar to make it look like the windows explorer folder view, then you must do this:
int num2 = (int)NativeMethods.GetWindowLong(treeView1.Handle, NativeMethods.GWL_STYLE);
num2 = NativeMethods.TVS_NOHSCROLL;
NativeMethods.SetWindowLong(treeView1.Handle, NativeMethods.GWL_STYLE, num2);

The pinvoke declarations for this exercise are in this NativeMethods file here.

For those of you that don’t want to repeat the above hacks for every single treeview in every single project, I’ve put all of the above in a TreeViewVista control. Just find a project that uses a TreeView already and change the ctor line to use TreeViewVista instead :-)

VS2005 SP1 RTM + SP1 Update Beta

Fri, December 15, 2006, 01:23 PM under Links
After installing the RTM version of Service Pack 1 for Visual Studio 2005, this is what will greet you the first time you run VS on Windows Vista:



It references the “SP1 Update” for VS2005 to make it run best on Vista. Note that even with that, the advice is still to run with administrative permissions. I have said before that you can get away with many things by not running VS elevated, but to play it on the safe side do follow the explicit advice given.

You can get a Beta of the SP1 Update for Vista here soon.

BTW, we are all familiar with the term “RTM” and we are all used to “SP”, but this “SP1 Update for Vista” is a new one. It made me smile but, if you think about it, what else could they have called it?

Launch elevated and modal too

Fri, December 15, 2006, 01:22 AM under Windows | Vista | UAC
Those of you that have attended my talks on UAC will have seen the demo where we extract a process and run it elevated (i.e. an elevation prompt requires the consent of the user). Here I want to add some extra juice to that one.

For the rest of you, basically, if you have some admin task in your application that you cannot redesign (i.e. get rid of), you still should not mandate that your whole application runs elevated (i.e. requires admin privileges). Instead, you should refactor that functionality in a separate process. When you require the use of that admin functionality from your main application, launch the other process elevated to do the work for you. There are a few ways you can launch the application elevated but the best one in this case is to manifest the application. An example of a manifest is here; change the level from asInvoker to requireAdministrator. Embed it in your project by pasting the following line in the “Post-build event command line” textbox of the project properties:
"$(DevEnvDir)..\..\Common7\Tools\Bin\mt.exe" -manifest "$(ProjectDir)$(TargetName).exe.manifest" –outputresource:"$(TargetDir)$(TargetFileName)";#1

So what is the extra juice I want to add in this post? Well there are two things that were nagging me with the way I showed how to launch the process.

One was that the UAC consent dialog that comes up was not modal to the main application (since it was being launched for another application). By default you do not observe this but since in my setup I have disabled the policy “Switch to the secure desktop when prompting for elevation”, it affects me [NOTE: I do not recommend you disable that policy, it just happens that I have it like that for historical irrelevant reasons]. I was tipped-off that to make the UAC dialog modal, you must pass to the ShellExecute call the handle of the main app.

The other thing I didn’t like was that if the process we launch elevated has its own UI, then that is also not modal to the application.

So here is the code that addresses both of the issues above:
private void LaunchElevatedProcess()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true; // default, but be explicit
startInfo.WorkingDirectory = Environment.CurrentDirectory; //or other if you prefer
startInfo.FileName = @"some_path_to.exe";

//// if the other process did not have a manifest
//// then force it to run elevated
//startInfo.Verb = "runas";

// Two lines below make the UAC dialog modal to this app
startInfo.ErrorDialog = true;
startInfo.ErrorDialogParentHandle = this.Handle;


try
{
Process p = Process.Start(startInfo);

// block this UI until the launched process exits
// I.e. make it modal
p.WaitForExit();

}
catch(Exception ex)
{
// user cancelled
MessageBox.Show(ex.Message, "caught it!"); //for demo purposes
return;
}
}

Enjoy :)

Managed Preview Handlers for Vista and Office

Wed, December 13, 2006, 02:25 PM under Windows | Vista
Truly fantastic article on MSDN magazine January 2007 issue: Managed Preview Handler Framework.

If you don't know what preview handlers are, on your Vista box open explorer, click on "Organise", "Layout" and then "Preview Pane". Now select a file and watch the preview pane. The file must be an office file or video or image and some others. For each file type/extension a preview handler exists that renders it in the preview pane (this also works for Outlook 2007 preview pane for attachments).

So how do you write a preview handler? Until now the answer was COM. Now with this article, Stephen Toub shares a framework that allows us to build them with managed code! Visit the article to download the framework which includes all the source code too.

Not only that, the download also includes preview handlers for files with extensions: bin;dat;csd;xps;xml;psq;isf;msi;pdf;resx;snk;zip and xaml. So even if you are not a developer caring about the framework, go get the download for the handlers themselves, to enrich your own Vista experience.

So, in a nutshell the framework has a simple inheritance hierarchy that encapsulates the COM ugliness and offers extensibility points for hooking in your own managed preview handler. When reading the article, if you are interested in the framework’s internals, keep this class diagram in mind. Another class diagram shown below should make clear how ridiculously easy it is to create these things now:

So to write a simple Hello World preview handler:
1. Create a new Class library, and reference the MsdnMagPreviewHandlers.dll from the article download.
2. Add a new code file and add to it these few lines of code.
3. Build the dll, gac it and regasm it (see the article if you have trouble with that, both tools are in your C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin folder)
4. Create a new file somewhere, test.moth and watch the preview:

Now do you see how extremely cool the Managed Preview Handler Framework is? Use it for your own file formats! At a future entry I'll show you a more meaningful preview handler.

BTW, if you have no interest in preview handlers, the code is still a great example of how to wrap COM APIs so read the article for the in-depth explanation of this diagram.

The day the world broke...

Wed, December 13, 2006, 03:16 AM under Random
OT post, no technical content on this one...

[sigh] I woke up this morning to the sound of my phone’s alarm. Unlike other times though, there is no notification. Without a notification, I cannot dismiss the alarm! None of the hardware buttons has any effect. I ended up muting the volume. Soft resets, playing with settings etc but still no joy. I am supposed to know this stuff and I can’t get this annoying alarm to stop sounding... Given that I had a conference meeting in 5’ I just left it muted and turned my attention to dialling the conference centre number. However, the person in charge of the call hadn’t activated it. So while waiting I thought I’d boot the laptop up and check email. Can’t connect to server; it could however download the 3 security updates fine and browse other internet sites. Checked another separate web email service and it was down as well! While trying VPNing in and finding that it is a no starter too, there is a loud bang on the door. I opened the door to find the postman informing me that the door bell seems to have broken. He handed me a letter I had to sign for.

As I was opening the letter (still waiting on the phone for the conf-call to be activated while observing that I still can’t connect to any email account and dreading to put the volume up on my phone in case the alarm started sounding again), I couldn’t help but think: “Will there be a message in the letter informing me that the ‘the world is broken today’...”. I was getting scared, in fact, I checked out of the window to see if there was anything unusual!

For the record: I eventually got into email via Redmond (rather than Reading), found a cancellation for the conf call, the other web email sprung to life, the letter wasn’t pleasant but not the end of the world. Door bell still broken, phone still on mute :-/

PDC 2007 in Los Angeles on October 2-5

Tue, December 12, 2006, 12:30 PM under Links
Save the dates. Hot off the press.

WinSAT

Tue, December 12, 2006, 07:47 AM under Windows | Vista
Do you remember the Windows Experience Index (earlier known as System Performance Rating)?

Well, it is available programmatically via the Windows System Assessment Tool (i.e. the WinSAT API). This is a COM API that, at a high level, gives you back the two things: the information and a bitmap.

Here is a screenshot of the output if I query the SAT on my laptop from C# console app. Console shows the details and the pop up windows form shows the bitmap


To read the full story, download the code to run on your machine and much more detail, please visit Bart’s blog entry now.

We want to speak at your company!

Tue, December 12, 2006, 02:31 AM under Events
Us:
We are the Microsoft developer and platform team in the UK.

You:
You are a company in the UK with a room that can hold 35+ people; your developer people!

The "contract":
You provide the room and people, we provide the entertainment. Well, I say entertainment, but what I mean is free presentations on developer aspects of Vista and Office. We’ll also throw some prizes on the day :-) Also, if you don’t mind, we’ll publicise your involvement and contribution!

What to do next:
Volunteer via email: mailto:msukdpetech@hotmail.co.uk

More details:
http://ukvistaofficelaunchtour.spaces.live.com/

Managed code and the Shell – Don’t!

Mon, December 11, 2006, 03:59 PM under dotNET
A few months ago when I was looking at what new Vista native APIs to play with from managed code, I was advised internally not to touch anything that is loaded in arbitrary processes. The short answer was that this has versioning implications.

Let's drill into it. If you write a shell extension of any sort with managed code, you have introduced a dependency onto the version of the CLR that you are using. The classic example is to think of all the managed applications on a computer that open a file dialog. Every time they do that, your .NET shell extension code gets injected into their process and bad things can happen (not just to the shell) but more importantly to those applications *IF* the version used in your managed extension, is not the same as the version used by that application. So the real root of this issue is the fact that each process can only load one version of the CLR combined with the fact that a version of the CLR can side by side on the same machine with other versions of the CLRs.

It sounds like we are pretty serious about this advice. An article written in 2004 demonstrating how to write namespace extensions with managed code was edited this June 2006 to include the following warning in red at the top of the article:
[ Editor's Update - 6/23/2006: Because shell extensions are loaded into arbitrary processes and because managed code built against one version of the runtime may not run in a process running an earlier version of the runtime, Microsoft recommends against writing managed shell extensions and does not consider them a supported scenario.]

Now at this point, some of you will have arguments and workarounds of how to avoid this limitation. I doubt they haven’t been raised already, but if you think you have something new to offer, go contribute to this extremely interesting discussion on the msdn forums (inc. contributions from Raymond Chen).

Vista and Office Launch event

Thu, December 7, 2006, 08:24 PM under Events
For my international readers outside the UK, you can take part in the UK Developer launch of Windows Vista and the 2007 Office System by following online the sessions on the two concurrent tracks:
- Vista Agenda
- Office Agenda

For UK residents I only have two words: REGISTER NOW!

Gadget in C#

Tue, December 5, 2006, 02:53 PM under Windows | Vista | SideShow
Goal
Walk through all the code required to write the SideShow gadget that we designed and showed screenshots of here.

Prerequisites
1. SideShow
2. Gadget Fundamentals
3. Designing with SCF
4. Microsoft.SideShow.dll

Installation/registration revisited
When talking about the basics of SideShow gadgets you saw how we need to create the appropriate registry keys and run a command for the Gadget manager to notify the user. You can actually achieve all of those actions in managed code and specifically with one line of code (I’ve separated the parameters into their own variable to make the line of code self-explanatory):
bool registerForAllUsers = false;
Guid gadgetId = new Guid("{65EA3E9A-8F83-4139-8139-94DE7E4149B0}");
string startCmd = String.Empty;
string iconPathNameAndResourceId;
bool onlineOnly = false;
Guid? propertyPage = null;

GadgetRegistration.Register(registerForAllUsers,
gadgetId, ScfSideShowGadget.ScfEndpointId, "The Moth", startCmd,
iconPathNameAndResourceId, onlineOnly, GadgetCachePolicies.KeepOldest, propertyPage);
To uninstall/unregister the gadget we need another line of code
GadgetRegistration.Unregister(registerForAllUsers, gadgetId);

ScfSideShowGadget class
Writing a gadget in managed code begins by creating a ScfSideShowGadget object (that you must remember to Dispose when your gadget exits). The way the gadget is associated with the registration/installation metadata is via the use of the same gadget GUID, of course. The following code snippet demonstrates that:
  ScfSideShowGadget gadget = new ScfSideShowGadget(new Guid("{65EA3E9A-8F83-4139-8139-94DE7E4149B0}"));
// send content to device
Sending glance data
Sending glance data is simply one line of code:
gadget.AddGlanceContent("some short summary \r\n" + DateTime.Now.ToLongTimeString() + "\r\n http://www.danielmoth.com/Blog \r\n Even more text all the way to the \r\n bottom");

Sending Images
Any images rendered on the SideShow-compatible device must be sent there of course and their content ids can then be referenced from the SCF XML snippets. The following code shows sending of the images:
string path = @"C:\Users\Public\Pictures\SideShow\";
string b = path + "SSForest.jpg";
string d = path + "SSgarden.jpg";
string m = path + "SSmenu.jpg";
string r = path + "SSdive.jpg";
gadget.AddContent(MothImages.Background, ImageContentTransforms.None, new Bitmap(b));
gadget.AddContent(MothImages.DialogIcon, ImageContentTransforms.KeepAspectRatio ImageContentTransforms.StretchToFit, new Bitmap(d));
gadget.AddContent(MothImages.MenuIcon, ImageContentTransforms.ReduceColorDepth, new Bitmap(m));
gadget.AddContent(MothImages.RandomImage, ImageContentTransforms.None, new Bitmap(r));
In the code above, MothImages is a simple class for holding the integer image content ids (as opposed to hard coding them in the body of the code).

Sending SCF content
As you’ll recall from the introduction to SCF, each page is its own SCF body tag. When sending pages to the device, we make a single method call per page that we want to send: a different overload of the AddContent method we already saw above for sending images. The code that follows is what was used to create *all* the screenshots of my previous SideShow blog post:
gadget.AddContent(MainMenuPage); //MainMenuPage is a property that returns a string
gadget.AddContent(ContextMenuPage); // ContextMenuPage is a property that returns a string
gadget.AddContent(ContentPageA); // ContentPageA is a property that returns a string
gadget.AddContent(ContentPageB); // ContentPageB is a property that returns a string
gadget.AddContent(ContentPageC); // ContentPageC is a property that returns a string
gadget.AddContent(DialogPage); // DialogPage is a property that returns a string
The above piece of code assumes that the properties we pass into the AddContent method calls return the XML as we designed it last time. This could look something like this:
public static string MainMenuPage
{
get
{
string content;
content = File.ReadAllText("page1.xml");
return content;
}
}
In the code above, page1.xml would hold the XML of this SideShow screenshot.

SCF creation revisited
So the above few lines of C# code register our gadget, create it and send both glance data and content data! The only thing it assumes is that we have created the SCF XML in a file already (i.e. in page1.xml).

However, Microsoft.SideShow.dll offers a class (Scf) with static methods (Body, Br, Btn, Clr, Content, Dialog, Div, Em, Img, Item, Menu, Txt) each with appropriate overloads that accept as parameters the attributes you would set on an SCF XML element and returns the equivalent XML. So, if you don’t want to hand craft the XML, you can get some intellisense help doing so programmatically (still no graphical way though).
For example, recall the screenshot of this XML and page? Here is the code that can generate that:
    content =
Scf.Body(
Scf.Menu(MothPages.MainMenu, "Main Menu Moth", ScfSelectAction.Target,
Scf.Item(MothPages.SomeText, "Points to 1st content page"), // 1st overload
Scf.Item(MothImages.MenuIcon, null, MothPages.WithImage, "Click for 2d one"), //2nd overload
Scf.Item(null, MothPages.ContextMenu, MothPages.MixedText, "This adds to the context menu"), // 2nd overload with context menu
Scf.Div(),
Scf.Item(MothMenuIds.Open, MothImages.MenuIcon, null, MothPages.DialogExample, "Shows dialog"), //3rd overload
Scf.Item(null, MothImages.MenuIcon, true, true, null, MothPages.MixedText, "IsDefault and points to 3rd content page"), // 4th overload
Scf.Item(null, MothImages.MenuIcon, false, false, null, MothPages.DialogExample, "I am !enabled"), // 4th overload, default & enabled
Scf.Btn(DeviceButton.Right, "Won't show up", MothPages.ContextMenu)
)
);
In the code above, any class starting with Moth is a simple class for holding the integer content ids. As a further example, the following screenshot shows some SCF XML and the c# code required to generate it (for the two pages that look like this and like that):

What’s left
Tons of stuff :-D
There are many more developer capabilities that we haven’t talked about on the SideShow platform and, instead of introducing them generically, I’ll introduce them as part of the managed API over subsequent posts... or maybe I should wait until we make Microsoft.SideShow.dll publicly available before doing so... let me know if you’d like to learn about it beforehand regardless...

Expression and WPF/e

Mon, December 4, 2006, 12:48 PM under Links
The exciting stuff I hinted at here are now... live!

Mike has all the useful links and accurate IMO commentary. BTW, you can catch both of us at the FOTB event tomorrow in Brighton.

Other link blogging about Expression or WPF/e: UX journey, WPF/e DevCenter, Wow indeed.

In case any of you are not getting with the programme in this new “UX matters” world, go visit the Microsoft Design Centre.