Authoring Sidebar Gadgets in C#

The latest release of Script# enables authoring Windows Vista Sidebar gadgets using C#. It also comes along with a sample gadget that enables searching MSDN content and a project template to get you up and running quickly.

Windows Vista Sidebar gadgets are essentially mini-HTML applications. The user interface is composed of pages containing regular HTML, CSS and images and the application logic is authored in JavaScript. So essentially you have the DOM, a scriptable Gadget API, and generally speaking, any other scriptable API at your disposal. Of course that implies, its relatively straight-forward to enable gadget authoring in C# via Script# as well. The latest release of Script#, 0.2.3.1 which was released yesterday, targets this scenario by providing APIs you can reference in your C# code. It also comes along with a sample gadget, and a project template.

The sample gadget included allows you to enter a search term or phrase that is queried against MSDN. It based on the MSDN search gadget sample written by Tim Heuer. I've added some features such as auto-complete, and saving past queries as per-user settings associated with the gadget. Its simple enough, yet demonstrates some interesting concepts.

If you're interested in using the gadget yourself, you can download and install it. If you're interested in picking apart the code and/or improving it, then read on... (it is available when you download and install Script#)

The gadget development overview on MSDN provides some introduction around core concepts. To summarize, at a high level, a gadget consists of a set of HTML pages, along with associated style sheets, images, and scripts packaged into a zip file renamed to a .gadget file. An xml manifest file describes the gadget such as the name of the main gadget HTML page, along with metadata such as title, author, copyright etc. In terms of the sample code, check out the following classes and snippets of code:

  • The main gadget page is shown in the sidebar. Its associated code-behind is the SearchScriptlet class Scriptlets are basically classes with a Main method that can be used as client-side code-behind for Web pages. These can be used in regular Web pages, but they make even more sense in gadgets which are essentially client-side applications.

    In addition to issuing queries, this class also shows the flyout page when search results are received. It tracks the docked state of the gadget which can be used to change the UI of the gadget depending on what mode it is in.

    using System;
    using System.DHTML;
    using System.Gadgets;
    ...
    
    public sealed class SearchScriptlet {
    
        private MSDNSearchResult _currentResult;
    
        static SearchScriptlet() {
            if (Document.Body.ID == "gadget") {
                Application.Current.Run(typeof(SearchScriptlet), null);
            }
        }
    
        private SearchScriptlet() {
            ...
            Gadget.OnDock = OnDock;
            Gadget.OnUndock = OnUndock;
    
            Gadget.Flyout.File = "Flyout.htm";
            Gadget.Flyout.OnShow = OnFlyoutShow;
            ...
        }
    
        public static void Main(Dictionary arguments) {
            SearchScriptlet scriptlet = new SearchScriptlet();
        }
    
        ...
    
        private void OnFlyoutShow() {
            DisplayResults(_currentResult);
        }
    
        private void OnSearchCompleted(MSDNSearchResult searchResult, object context) {
            ...
            _currentResult = searchResult;
            Gadget.Flyout.Show = true;
        }
    
        private void OnDock() {
            UpdateDockedState();
        }
    
        private void UpdateDockedState() {
            DOMElement body = Document.Body;
            if (Gadget.Docked) {
                Element.RemoveCSSClass(body, "undocked");
                Element.AddCSSClass(body, "docked");
            }
            else {
                Element.AddCSSClass(body, "undocked");
                Element.RemoveCSSClass(body, "docked");
            }
        }
    }
    
  • The flyout is implemented as another independent page and its associated code-behind is implemented in the SearchResultsScriptlet class.
  • The app contains an MSDNSearch class, which is responsible provides utility methods for issuing queries and fetching RSS feeds containing query results. This class also uses the gadget settings API to store search queries (serialized using JSON) into the user's preferences in an MRU list.
    internal static class MSDNSearch {
    
        public static void Search(string query, SearchCompletedCallback callback, object userContext) {
            AddMRUEntry(query);
            string uri = String.Format(SearchUrlFormat, query.EncodeURIComponent());
    
            HTTPRequest searchRequest = HTTPRequest.CreateRequest(uri, HTTPVerb.GET);
            searchRequest.Invoke(delegate(HTTPRequest request, object context) {
                                     MSDNSearchResult searchResult =
                                         new MSDNSearchResult(query, request.Response);
                                     callback(searchResult, userContext);
                                 }, null);
        }
    
        private static void AddMRUEntry(string entry) {
            ArrayList entries = GetMRUEntries();
            ...
            entries.Insert(0, entry);
            Gadget.Settings.WriteString("MRU", JSON.Serialize(entries));
        }
    
        public static ArrayList GetMRUEntries() {
            if (MruList == null) {
                string mruValue = Gadget.Settings.ReadString("MRU");
                if (String.IsNullOrEmpty(mruValue)) {
                    MruList = new ArrayList();
                }
                else {
                    MruList = (ArrayList)JSON.Deserialize(mruValue);
                }
            }
            return MruList;
        }
    }
    
  • The SearchResultScriptlet uses the AutoComplete behavior to show past queries. One thing to notice here is how the code uses the local MRU list to generate auto-complete suggestions, rather than working against a Web service. Other behaviors used in the project include WatermarkBehavior and EnterKeyBehavior - all of these are part of Script# and they can be used in gadget UI development just as they can be used in regular Web pages.
    public sealed class SearchResultsScriptlet {
    
        private SearchResultsScriptlet() {
            TextElement searchTextBox = (TextElement)Document.GetElementById("searchTextBox");
    
            AutoCompleteOptions autoCompleteOptions = new AutoCompleteOptions("");
            autoCompleteOptions.minimumPrefixLength = 1;
            _autoComplete = new AutoCompleteBehavior(searchTextBox, autoCompleteOptions);
            _autoComplete.RequestingItems += OnAutoCompleteRequestingItems;
        }
    
        private void OnAutoCompleteRequestingItems(object sender, AutoCompleteRequestEventArgs e) {
            ArrayList mruList = MSDNSearch.GetMRUEntries();
            if (mruList.Length != 0) {
                string prefixText = e.PrefixText.ToLowerCase();
                mruList = mruList.Filter(delegate(object item) {
                    return ((string)item).ToLowerCase().StartsWith(prefixText);
                });
            }
            e.SetItems((string[])mruList);
        }
    }
    
There are two key things to infer from the code. First, anything you can do in regular Web pages, you can also do in gadgets (sometimes more, given the gadget is trusted and runs outside the browser sandbox). Second, you can now author gadgets in C#... I intentionally chose to show the C# code. Of course it gets compiled to script, which is what gets included into the final gadget zip package.

It will be interesting to see what useful gadgets are developed to make the sidebar screen real estate live up to its potential. Script# comes along with a project template to get you started on the path to writing some of those gadgets. When you install the latest build, a "Script# Sidebar Gadget" project template will be available to choose from to create a New Project in Visual Studio. This is essentially equivalent to a C# ClassLibrary project, with some additional content such as starter pages, style sheets, xml manifest, and some images to get you started quickly. You'll want to make sure you fill in appropriate metadata values specific to your gadget in the xml manifest.

To test the gadget simply zip up the contents along with generated scripts, rename the .zip file to a .gadget file, and double click this file to get the resulting gadget installed.

Update, 6/10/07: Fixed the gadget because of changes to the MSDN web service, and uploaded to the Windows Live Gallery

Posted on Tuesday, 2/13/2007 @ 4:37 PM | #Script#


Comments

41 comments have been posted.

Carlos Yakimov

Posted on 2/13/2007 @ 8:24 PM
If I translate this code to Vb.net It will work ? Can I do gadgets with vb.net ? (Vs2005 Of Course =) ...)

Nikhil Kothari

Posted on 2/13/2007 @ 11:32 PM
Unfortunately there is no support for VB. Script# only translates from C# to JavaScript, though theoretically you could convert from VB to C# and then use script#... :-)

Keith J. Farmer

Posted on 2/14/2007 @ 4:17 AM
Increasingly cool. Perhaps add an MSBuild targets file?

Perhaps a way to reference the ASP.NET AJAX scripts?

Michael

Posted on 2/14/2007 @ 8:37 AM
I had a look at the sample and the template but there's one thing i don't get. how does the gadget know which c# class to run from?

Nikhil Kothari

Posted on 2/14/2007 @ 9:43 AM
All the c# classes in the project get compiled into MSDNGadget.js which is included into the different HTML pages. The <body> tag of the different pages have ids, such as "gadget", and "gadgetFlyout". Given that, here's how SearchScriptlet runs...

The SearchScriptlet has a static ctor, as shown in the first code snippet in the post - this ctor checks if the ID of the body is "gadget", and if so, it tells the global Application object to run the SearchScriptlet scriptlet. The Application object (which comes from the Script# Framework), essentially calls the Main method of the specified scriptlet. The Main method in turn instantiates an instance of the Scriptlet class.

Correspondingly, in the Flyout page, the SearchResultScriptlet's static ctor checks if the ID is "gadgetFlyout", and does the same thing.

This is very much like a Windows app - where execution begins at the Main method. The only thing special here, is your .js file might have multiple Main methods - hence the need for a static ctor to select which scriptlet to run based on which page is being rendered. Hope that answers Michael's question.

Joe

Posted on 2/24/2007 @ 1:53 PM
It is an interesting article, unfortunately the link Projects/ScriptSharp appears dead, as does the Projects link. Bookmarked anyway, I'll pop back in a few days.

Jahn Otto Andersen

Posted on 2/26/2007 @ 3:17 PM
First of all, thank you very much for an extremely useful tool! I've just started developing sidebar gadgets, and Script# make life so much easier!

I've got two questions:

1) Is there any API documentation available anywhere?

2) I've created two classes, and I'd like to have one of them listen to events from the other one. I'm trying to follow the documentation in the pdf document, but it seems like I'm not doing it correctly. It compiles, but ends up with a JavaScript error as soon as my event is fired.

Here's the class that fires the event:

public class A
{
private EventHandler m_listChangeHandler;
public event EventHandler ListChanged
{
add { m_listChangeHandler = (EventHandler)Delegate.Combine(m_listChangeHandler, value); }
remove { m_listChangeHandler = (EventHandler)Delegate.Remove(m_listChangeHandler, value); }
}

...

public void SomeFunction()
{
if (m_listChangeHandler != null)
m_listChangeHandler(this, new EventArgs()); // <-- It fails here!
}
}

And here's the class that listens:

public class B
{
private A _a;

public B()
{
_a.ListChanged += new EventHandler(this.OnEvent);
}

private void OnEvent(object sender, EventArgs e)
{
...
}
}

Am I doing anything wrong here?

Peter

Posted on 2/28/2007 @ 4:05 AM
this is, in lack of more praising words: awesome!

your work always keep me amazed, thanks man!

P.

rajesh

Posted on 3/8/2007 @ 5:15 PM
Check the soapbox gadget i created recently

www.codeproject.com/useritems/SoapBoxGadget.asp

Some One

Posted on 3/20/2007 @ 9:00 AM
Just great this is awsome. I think MS shot them selves in the foot by buiding up a bunch of .net and C# programmers only to have vista gadgets use HTML and JavaScript. Like my Vista Gadget is going to run on linux or a mac hello Bill get a clue you trained us on C#/.net now eat your own dog food. If not someone else will and has, thank you this is awsome.

Aditya

Posted on 3/24/2007 @ 2:43 PM
Absolutely brilliant. I originally used C# by compiling it into a COM-visible DLL, and then using ActiveX, etc. etc. but Script# seems to be precisely what I need (hopefully). Many thanks!

amitairos

Posted on 3/26/2007 @ 7:55 AM
I'm using Visual Web Developer and I want to know how to use Script# with it. For instance, the "Hello World" application that is in the pdf document of Script#- how do I turn it into a gadget?

Aditya

Posted on 3/26/2007 @ 10:50 PM
Nikhil,

As far as I can tell we wouldn't be able to use Script# for building a sidebar POP3 checker, correct? Is there some way this can be done? Using an ActiveX DLL like I mentioned above causes problems, namely that the gadget freezes periodically, and I don't even keep the sidebar open anymore because of it.

Nikhil Kothari

Posted on 4/2/2007 @ 12:16 AM
Aditya, you can package up some non-UI related functionality in an activex object implemented in c#, and expose that to script. To use it from script#, all you need to do is write a stub class that provides metadata about the OM of the activex object (see the pdf for a sample on exactly this). If you're doing blocking network operations, you should be doing those on a background thread - if you do it on the main UI thread, you're going to block the UI thread, and freeze the UI...

Amitairos - You should get Visual C# Express (also free) and then install Script# - that will create a Gadget class library project in your templates, that you can use to get started with.

nakliyat

Posted on 4/19/2007 @ 1:49 AM
thank you very nıce muck vary very comment...

Niranjan

Posted on 5/25/2007 @ 3:53 AM
Hi Nikhil,
Iam new to this gadgets concept. I would like to do a Windows Sidebar Gadget. What should be my system requirement. Iam having Windows XP OS.

newkon

Posted on 5/27/2007 @ 2:02 AM
very very nice information thanks..
realy nice blog.i will come every time here.thankss.

Atul

Posted on 5/30/2007 @ 1:41 AM
I have some more basic issues. 1. I can't find where Script# got installed and hence where is this sample located. I downloaded the one attached to this article and installed it. 2. I get MSDN Search gadget appear on my side bar, but it doesn't seem to search anything? Am I missing something here? It seems to do some search, but returns without any results.

Rajesh Lal

Posted on 6/20/2007 @ 2:09 PM
Thats an awesome gadget, I too have created a few check

Dilbert Gadget at www-DOT-csharptricks-DOT-com-SLASH-Articles-SLASH-DailyDilbert-DOT-aspx and

Soapbox Video gadget here www-DOT-csharptricks.com-SLASH-Articles-SLASH-SoapboxVideoGadget-DOT-aspx

best

kurian

Posted on 7/21/2007 @ 5:34 PM
I was working on a vista gadget to monitor the status of packaging. Everyhting seems to work fine except for the flyout. When I click a cell to activate the flyout, the gadgets main body goes blank for a second and then comes back along with the flyout. Any help to resolve this will be appreciated.

Matt Sharpe

Posted on 8/22/2007 @ 1:26 PM
I have been coding a gadget that makes use of WMI and the System.Management classes. However I cannot get it to build because using System.Management ends up requiring me to reference mscorlib, which breaks the Script type projects.

sohbet

Posted on 9/25/2007 @ 5:54 PM
thank you friendss

Kurye

Posted on 10/24/2007 @ 10:03 AM
Thanks for this informations. yararli bilgiler icin cok tesekkurler. (escuse me my english is bad.)

lucian

Posted on 11/13/2007 @ 11:46 AM
I am currently using Visual Studio 2008 beta and I can find the project template... When I create a new project, there is nothing like "Script# Sidebar gadget" I've tried to find it another way, but was unsucessful... any help?

oyunlar

Posted on 11/25/2007 @ 3:29 PM
thank you

ook

Posted on 12/10/2007 @ 6:34 PM
Well if I can create an ActiveX in C# then this Script# would be useful. Does anyone know how to create and ActiveX in C# (That is acceptable to Script#)?

sepehr

Posted on 1/8/2008 @ 12:53 AM
thank you for this usefull topic
how can i use system.globalization in gadget?
thanks

Jani

Posted on 3/26/2008 @ 3:20 AM
Ah this made my gadgetty life so much easier!

John

Posted on 4/13/2008 @ 3:41 AM
Hello guys thats such as very nice BLOG ...... enjoy.....

Arnold

Posted on 5/14/2008 @ 10:30 PM
hey can somone tell me how to find what urls the gadgets get their updates from? i need to open them up individually with mt web filter??
pls email me
thnx

Chris

Posted on 7/7/2008 @ 8:14 PM
This is a great article, makes my life easier starting into sidebar gadgets.

I have been looking at the sample project, and have created my own, and im looking for a bit of assistance. What i really need is the ability to create an HttpListener like in c#, but if that is not possible, can i use script# to create a timer that could run on an interval to poll a URI instead.

Thanks,

Chris.

Yann

Posted on 7/8/2008 @ 8:32 AM
You can also create gadgets in C# and VB.NET with myBoard (http://myboard.yannalet.com)

Nice article though ...

Peter

Posted on 7/22/2008 @ 9:30 PM
Hi! I am new on this... can you give an example of gadget proyect?
Thanks!

tom

Posted on 9/4/2008 @ 8:42 PM
where can I download the code for this sample?

Chris

Posted on 9/23/2008 @ 4:23 PM
Great Stuff! This is exactly what I was looking for today. Don't stop!

ioWint

Posted on 12/12/2008 @ 10:09 AM
can u plz upload the code for the solution.. its a gr8 work.. but it would hav been realy gr8 if u could have explained it in a sequential flow ryt from creating a script# project using gadget template to completion. And in th above code, i couldnt find the undock() method definition, its giving me compile error.. can u plz upload the exact project u used to create the gadget uploaded @ the gallery.live.com!?
n btw, i think the template could be modified to show something, rather jus blank when made a gadget and installed :)
thanks
ioWint

Christopher

Posted on 3/24/2009 @ 2:24 AM
Hello

I have a problem with Script#, it compile javascript that doesn't work at all. I checked the debug file after compiling and the code makes no sense in some places. Even the MSDN sample doesn't
work when I compile it and adds it to the vista sidebar. Whats wrong with my C# code?

using System;
using System.DHTML;
using System.Gadgets;
using ScriptFX;
using ScriptFX.UI;

public class GadgetScriptlet
{
public GadgetScriptlet()
{
Gadget.Flyout.File = "Flyout.htm";
}

public void toggleFlyout()
{
Gadget.Flyout.Show = true;
}
}

Thanks in advance.

stricq

Posted on 8/21/2009 @ 10:08 AM
The text above says the MSDNSearch gadget is included. I cannot find it anywhere. Does anyone know where it it stored?

Nilay Kothari

Posted on 11/23/2009 @ 5:21 AM
When i use Script# library and create a gadget, it seems to show "system is undefined" error on ssgadget.js file in IE 8 and Windows 7 OS. Is this a known issue? Is there a work around available?

Please let me know since this is a blocking issue for us.

Jimmy

Posted on 1/18/2010 @ 8:33 PM
But where is the code?

Karan

Posted on 2/21/2010 @ 10:21 AM
This article is really good.!!
Guys, i am facing a basic problem. Please help me out.

"After double clicking the .gadget file, the gadget is not getting installed in Win 7 machine"

I have following steps to create a simple gadget :-

1. Used the Windows Sidebar Gadgets project template in Visual Studio 2008.
2. Added the following code (line3-4) in GadgetScriplet.cs
public static void Main(Dictionary arguments) {
GadgetScriptlet scriptlet = new GadgetScriptlet();
DOMElement domElement = Document.GetElementById("welcomeLabel");
domElement.InnerText = "Hello World!";
}
3. Changed the Gadget1.xml to following :-
<?xml version="1.0" encoding="utf-8" ?>
<gadget>
<name>Gadget1</name>
<namespace>Gadget1</namespace>
<version>1.0.0.0</version>
<author name="Karan Vohra">
<info url="http://www.microsoft.com" />
<logo src="Logo.png" />
</author>
<copyright>Copyright (c) 2007</copyright>
<description>This is it</description>
<icons>
<icon height="48" width="48" src="GadgetIcon.png" />
</icons>
<hosts>
<host name="sidebar">
<base type="HTML" apiVersion="1.0.0" src="Gadget.htm" />
<permissions>Full</permissions>
<platform minPlatformVersion="1.0" />
<defaultImage src="Gadget.png" />
</host>
</hosts>
</gadget>

4. Then I packaged the Content folder to “Gadget1.zip”.
5. Logged into Win7 Machine and renamed it to “Gadget1.gadget”.
6. Double-clicked on the Gadget1.gadget file.
7. The dialog box to install it came and I clicked on “Install” button.

Still I cant see the Gadget installed in Windows 7 machine..

Can someone help me?

Thanks in advance!
Post your comment and continue the discussion.