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