Archive for July, 2008

July 30, 2008: 6:57 pm: Dan.Net, Programming

Here’s a continuation of my list of coding tips and samples for the Infragistics NetAdvantage suite.  Part 1 dealt with the UltraGrid control, and I could actually devote Parts 2 through GigaMegaZillion® to the UltraGrid since there are so many facets to it.  I’ll return to the UltraGrid in future articles — today, for variety’s sake, let’s take a look at a considerably more narrowly focused tool, the UltraToolbarsManager.

(Incidentally, most of the the controls and classes in the Infragistics NetAdvantage suite were given the "Ultra" prefix awhile back, but the generally excellent NetAdvantage documentation still refers to them by their old "Win" prefix, and the namespaces have a prefix of UltraWin.  Go figure.  Anyway, in this article I’m using the Ultra prefix.)

The UltraToolbarsManager has a similar name to the .Net Framework’s ToolStripManager, but it plays a far more central role.  While the ToolStripManager is really just a toolstrip sidekick, relegated to merging and "rafting" toolbars and menubars, the UltraToolbarsManager lives up to its name — it owns all of the toolbars, menubar and context menus on the form, and all your code which accesses these objects needs to go through the manager. 

This makes it relatively easy to figure out the syntax for most toolbar-related properties and methods — just type the name of your UltraToolbarsManager control and let Intellisense guide you along.  It also makes it relatively easy to configure your toolbars and menubars at runtime rather than design time, since the code that creates a toolbar is almost identical to the code which creates a menubar or context menu.

Personally, I find the code easier to deal with than the UltraToolbarsManager designer, which is slow and surprisingly limited when it comes to the populating of your menus and toolbars. I tend to just drag an UltraToolbarsManager onto my form, let Infragistics automatically create the container you need to dock the toolbars and menubars, then add an empty menubar using the default settings. (The Infragistics designer applies some special settings for a menubar which aren’t worth coding from scratch). The form can then pass a reference to the UltraToolbarsManager object to the code that I describe below which configures things the way I want them.

As in Part 1, the code samples are based on the Windows Forms edition of "NetAdvantage for .NET 2007 Volume 1 CLR 2.0".  I’m pretty sure that they would work with more recent versions of NetAdvantage — if not, then stay tuned for "Infragistics NetAdvantage Tips – Part X: Dealing with Broken Compatibility after Upgrading"!

Here’s a generic initialization method that I use in every form in our application – it enforces certain properties that all our forms share:

public static void Infragistics_InitializeToolbarsManager(
    UltraToolbarsManager toolMgr)
{
        // set the transparency colour in toolbar button icons
        toolMgr.ImageTransparentColor = System.Drawing.Color.Magenta
        // don't allow the user to add or remove buttons
        toolMgr.ToolbarSettings.AllowCustomize = DefaultableBoolean.False;
        // don't allow the user to hide the toolbar completely
        toolMgr.ToolbarSettings.AllowHiding = DefaultableBoolean.False;
        // allow menubar and toolbar to be dragged onto same line
        toolMgr.LockToolbars = false;
        if (toolMgr.Toolbars.Count > 0)
            // allow menu bar and toolbar to be put on same line
            toolMgr.Toolbars[0].IsMainMenuBar = false;
}

All the form has to do is pass a reference to its UltraToolbarsManager control:

Infragistics_InitializeToolbarsManager(ultraToolbarsManager1)

The two main objects that are used to build a toolbar or menubar are the ButtonTool (toolbar buttons and menu entries) and PopupMenuTool (pulldown menus and context menus).  These are fairly similar to the .Net Framework’s ToolStripMenuItems — so similar, perhaps, that Infragistics deemed them unworthy of the honorific "Ultra".

There aren’t many interesting properties for the PopupMenuTool, so I just create them with their default settings:

popupMenu = new PopupMenuTool("File");
// the UltraToolbarsManager owns everything!
ultraToolbarsManager1.Tools.Add(popupMenu);
toolbar1.Tools.AddTool(popupMenu);

There are a number of useful settings for the ButtonTool, which can be an icon on a toolbar or menu entry.  Here’s a method that we use to create a ButtonTool regardless of where it is going to be located:

public static ButtonTool Infragistics_CreateButton(string strKey, string strCaption,
    object image, ToolDisplayStyle style, Shortcut shortcutKeys)
{

        ButtonTool button = new ButtonTool(strKey);
        button.SharedProps.DisplayStyle = style;
        try
        {
            // use same image for small and large toolbars
            button.SharedProps.AppearancesSmall.Appearance.Image = image;
            button.SharedProps.AppearancesLarge.Appearance.Image = image;
        }
        catch (Exception)
        {
            // image not found, so make it text only
            button.SharedProps.DisplayStyle = ToolDisplayStyle.TextOnlyAlways;
        }

        button.SharedProps.Caption = strCaption;
        button.SharedProps.Shortcut = shortcutKeys;

        return button;
}

The parameters passed to this method are self-explanatory except for ToolDisplayStyle: this is used to specify whether the button will be just an image, just text, or both.  One convenient setting is TextOnlyInMenus, which allows the same ButtonTool to appear as text if located in a menu and an image if located in a toolbar.  You might find that you use the same ButtonTool instance 3 times: once in the main menu, once in a toolbar and once in a context menu.

This "CreateButton" method becomes the basis for methods which populate toolbars, menubars and context menus.  For any of the three, the form passes an array of settings:

  1. button key
  2. button tooltip
  3. button image
  4. start of group indicator — if true, a separator line is added to the menu or toolbar before this item
  5. tool display style, as described above
  6. shortcut keys, if any

The method which applies these settings looks like this. (You’ll probably want to add code to allow the caller to use defaults for some settings, but I’ve omitted that code to keep things simple):

private static void addTools(UltraToolbarsManager toolMgr,
    ToolsCollection tools, object[,] buttons)
{

     for (int intColCounter = 0; intColCounter < = buttons.GetUpperBound(0); intColCounter++)
    {

        ButtonTool button = Infragistics_CreateButton((string)buttons[intColCounter, 0],
            (string)buttons[intColCounter, 1],
            buttons[intColCounter, 2], (ToolDisplayStyle)buttons[intColCounter, 4],
            (Shortcut)buttons[intColCounter, 5]);
        if (button != null)
        {
            toolMgr.Tools.Add(button);
            tools.AddTool(button.Key);
            // NOTE: first in group can't be set until the button is added to its parent
            tools[tools.Count - 1].InstanceProps.IsFirstInGroup = (bool)buttons[intColCounter, 3];
        }
    }
}

For example, to add buttons to a toolbar a form might call: 

Infragistics_InitializeToolBar(ultraToolbarsManager1, "MainToolbar",
    new object[,] {
    { "SaveButton", "Save", Images.Save1, true,
       ToolDisplayStyle.TextOnlyInMenus, Shortcut.CtrlS },
    { "RefreshButton", "Refresh", Images.Refresh, false,
       ToolDisplayStyle.TextOnlyInMenus, Shortcut.F5 },
    { "PrintButton", "Print", Images.Print1, false,
       ToolDisplayStyle.TextOnlyInMenus, Shortcut.CtrlP }
});

In the above code, "Images" is Resources File, added with Visual Studio’s Project->Add New Item menu, which contains all of our bitmaps and icons.

And here’s the code that creates that toolbar:

public static void Infragistics_InitializeToolBar(
    UltraToolbarsManager toolMgr,
    string strToolBarKey, object[,] buttons)
{

        // create the toolbar
        UltraToolbar toolBar = new UltraToolbar(strToolBarKey);
        toolMgr.Toolbars.AddToolbar(strToolBarKey);
        // create the toolbar buttons
        addTools(toolMgr, toolMgr.Toolbars[strToolBarKey].Tools, buttons);
}

Similarly, you can create a context menu by passing the same array to a slightly different method:

public static void Infragistics_InitializePopupMenu(
    UltraToolbarsManager toolMgr,
    string strMenuKey, object[,] buttons)
{
    // create the popup menu
    PopupMenuTool menu = new PopupMenuTool(strMenuKey);
    toolMgr.Tools.Add(menu);

    // create the toolbar buttons
    addTools(toolMgr, menu.Tools, buttons);

}

The form would use this method to create a context menu for a grid as follows:

    Infragistics_InitializePopupMenu(ultraToolbarsManager1, "GridContextMenu",
    new object[,] {
    { "Copy", "Copy", Images.Copy1, false,
      ToolDisplayStyle.ImageAndText, Shortcut.CtrlC },
    { "Paste", "Paste", Images.Paste1, false,
      ToolDisplayStyle.ImageAndText, Shortcut.CtrlV },
    { "Delete", "Delete", Images.Delete, false,
      ToolDisplayStyle.ImageAndText, Shortcut.Delete }
    });

    // set grid context menu
    ultraToolbarsManager1.SetContextMenuUltra(grdTest, "GridContextMenu");

Like a true micromanager, the UltraToolbarsManager insists on handling all the action, too.  When the user selects an option from a toolbar, menubar or context menu, it’s the UltraToolbarsManager’s ToolClick event that gets fired.  This makes it easy to use the same code to perform the same action regardless of how the user invoked it, , but sometimes you need to know what the context of the action is: for example, which grid does the user want to paste into. If the user selected the action using a context menu, you can use an event parameter to tell you which context menu:

if (e.Tool.OwningMenu != null)
    if (e.Tool.OwningMenu.Key == "GridContextMenu")
    {
         // oh, you mean the grid!
    }

But if the action was invoked using a shortcut key, the event parameters won’t help you. As a workaround, I check the form’s ActiveControl to get the context, but this is one area where I wouldn’t mind if Infragistics made my code obsolete in new versions.

July 21, 2008: 6:48 pm: Dan.Net, Programming

ClickOnce, the software update package that Microsoft introduced in Visual Studio 2005, might be a convenient and secure way to distribute updates to users over the Internet.  I wouldn’t know, since we don’t do that.  Our application is a turnkey system whose updates need to retrieved from an internal server at our clients’ sites, and I do know that ClickOnce is an inconvenient (but secure) way of doing that. 

The problem is that the URL from which the updates can be obtained is specified when the system is published.  That’s fine if all of your users can connect to the same URL, and you can ensure that the URL will remain the same.  It’s a pain if users at 20 different sites need to connect to 20 different update servers, and it’s a royal pain if you have no control over whether the names of those servers will change.  For us, ClickOnce was PublishTwentyTimes.

What you need is an easy way to change the update URL after the files have been published.   Just editing the files won’t do the trick, since the manifest is signed with a certificate — or, more specifically, the manifest contains a hash value that is generated with a key.  If you change anything in the published files, this hash value needs to be recalculated.

As it turns out, there is a relatively straightforward workaround for this.  Although our situation is not (I think) that uncommon, and the workaround uses a tool that is a standard part of the .Net Framework SDK, the procedure doesn’t seem to be well known or well documented.  So, I thought it might be useful if I listed the steps involved.

Before starting, you’ll need to have the certificate that was used to sign the manifestwhen the files were published.  If you were the one that did the publishing, then you’ve already got it.  If the publishing was done on another PC, and you’re still using the temporary key generated by Visual Studio, you can export it from Visual Studio on the other PC by clicking on the "Create Test Certificate" button in the Signing tab of the Project Properties dialog, and import it into Visual Studio on your PC using the "Select From File" button on the Signing tab.  If you are using a certificate from a signing authority then, well, talk to them since they’re the authorities.  

1. Follow the standard steps for publishing a ClickOnce update.  The install files will be written out to the "Publishing Location" that you specified in the Properties dialog of your project, as shown below.

Publishing Location field

2. Copy the files from the "Publishing Location" to another folder.  This copy of the files will be modified to use a new URL for distributing the updates.   If this is the first version that you’ve published then you’ll just copy everything from the "Publishing Location" folder.  Otherwise, you’ll need to copy the files for your most recent version:

  • <YourAssemblyName>.application
  • <YourAssemblyName_YourVersionNumber>.application (e.g. YourApp_1_0_0_0.application)
  • publish.htm
  • setup.exe
  • the folder named <YourAssemblyName_YourVersionNumber>

3. Run MageUI. It is part of the .Net Framework SDK (which can be downloaded from Microsoft), and is also installed as part of Visual Studio.  It’s not accessible from the Visual Studio IDE or the Start menu, so you’ll have to launch it the hard way.  In Visual Studio 2005, it’s located at Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\mageui.  Another way of launching it is to open the .NET Framework SDK Command Prompt (which is on the Start menu) and type “mageui” at the command prompt.

4. In MageUI, select File->Open, or click the Open icon on the toolbar.  Select the application manifest (e.g. YourApp.application) in the folder to which you copied the files in step 2.

5. Select Deployment Options.  Change the “Start Location” to the URL  from which your users will grab the updates. 

Deployment Options

Having (finally) made the change you needed, you now to need to prove your credentials.

Signing Options6. Click on Application References.  Click the "Select Manifest" button.  Open the folder for your current version (e.g. YourApp_1_0_0_0) and select the .manifest file (e.g. YourApp.exe.manifest).

7. Select File->Save, or click the Save icon on the toolbar.  A Signing Options dialog will be displayed.  Here’s where you’ll need to select the certificate that was used when the install files were originally published, as described earlier.  Click OK, and a new hash code will be generated for your updated files.

8. Repeat steps 4 through 7 for the version-specific application manifest (e.g. YourApp_1_0_0_0.application)

There, wasn’t that easy?  Well, easier than building the install files 20 times?  Trust me, it becomes much easier once you delegate this tedious (but secure) process to someone else!

July 12, 2008: 7:43 pm: DanGadgets

Nokia recently released the “Diablo” update for the N800/N810 Internet Tablet.  This a relatively minor update to their OS 2008 firmware, but if you’ve been having problems with battery drain (as I have) then you should definitely give Diablo a try.

The main benefits of the upgrade have been written about elsewhere:

  • A noticeable performance boost in its Mozilla-based browser.  I found the improvement most welcome in Google Reader, which now performs quite acceptably on my N800.
  • A new e-mail client named Modest.  Modest, unlike the default e-mail program on the original release of OS 2008, gets along well with Gmail’s IMAP service, and is much faster than my previous favourite, Claws.  The only complaint I have about Modest is that it has no option for displaying images in e-mail, but a relatively simple fix for this can be found here.
  • An improved Application Manager which runs reliably in the background (the previous version ran unreliably even in the foreground). 

Since this update also allows future updates to be installed without “reflashing” (i.e. reinstalling all your apps and restoring all your settings from backup), there are plenty of reasons for N800/N810 owners to take advantage of this upgrade.

The improvement that has me the most excited, though, is one that hasn’t been mentioned elsewhere.  As I’ve written previously, my N800 is a “light sleeper” – when left in low power “sleep” mode the battery would mysteriously drain.  Since I had no explanation and found no workaround, my only option was to close all the apps and shutdown the device when I was finished using it, then boot it up the next time, which defeated much of the convenience of a portable PC.

Thanks to Diablo my N800’s insomnia has been solved.  It now works the way it was intended – when I’m finished using it I just slip it in my pocket and let its power management software worry about the battery usage.  

This particular benefit of Dialbo wasn’t widely noticed because the original problem didn’t affect most N800s. It seems that a batch of N800s and N810s bought in late 2007 and early 2008 had a flaw with their power management.  Nokia released a minor fix to the firmware in February that fixed a power-on problem in these devices, and now it appears that Diablo has made another adjustment that fixed the battery drain.  Admittedly, all of this is speculation since Nokia didn’t announce any change to power management as part of Diablo, and it seems that the upgrade has caused battery drain problems for some devices and fixes them for others.  Still, if you’ve been having problems with the battery usage of your N800/N810, be sure to give Diablo a try!

July 7, 2008: 5:38 pm: DanUncategorized

This is a rare post that isn’t directly about programming or technology, but I wanted to pay tribute to a truly fascinating web site put together by a fellow resident of our highrise in west Toronto.

Back in late March we were surprised to find that our building had become home to a couple of ornithological celebrities: two peregrine falcons.  These birds are an endangered species in Canada (and many other parts of the world), nearly wiped out in the 1970s by DDT poisoning.  Since they love high perches and pigeons, peregrines are not uncommon residents in large cities, and the Canadian Peregrine Foundation’s web site lists a number of nests in the Greater Toronto Area.  For whatever reason, though, it is rare for these birds to choose a residential building as their nest site.  Ours is the only such building in Toronto, and one of only 2 in the province.  It’s our building’s biggest claim to fame since Blue Jays’ shortstop Luis Sojo lived here in the 90s.

Over the past few months we’ve enjoyed following the comings and goings (at up to 200 km/h) of our new neighbours, through bad times (they abandoned their first nest after all of the eggs failed to hatch) and good (they went 3 for 3 with the eggs in their second nest).  You can follow them too, thanks to the Peregrine Falcon Zone 2008 web site set up by building resident Matthew Rossi.

Peregrine Falcon
Peregrine Falcon
Matthew has combined his talent for photography and web site design to put together a fantastic photojournal of the falcons’ lives at the condo.  If you want to see what a peregrine falcon looks like up close, or in flight, or at just 1 day old, or tearing the head of a blue jay (not Luis!), here’s your chance.  Trust me, you’ll get an even better look at the falcons through these photos then you will by being on-site. 

When the falcon’s second batch of eggs approached their due date, Matthew began adding daily nest observations to go with the photos, including the drama of the 1st hatching (after a night of near-biblical rainfall), the 2nd later the same day and, after a tense 24 hours of watching the last egg lie unincubated, the third.

This weekend live video was added to the site.  Since the nest is on the north tip of the building and the protective parents made it unadvisable to setup a camera on the roof or a nearby ledge, the video is being shot from a camera outfitted with a high zoom lens positioned inside another building.  Throw in the additional challenge of compensating for the glare off the concrete building and the shadows cast by the side of the ledge, and the resulting video quality is amazing, much better than I can get with my 8×40 binoculars. 

Matthew recently gave the site a graphic redesign to make it, in my humble opinion, the best peregrine falcon site on the Web.  Check it out!  Then come back in a few days and check again — those little suckers are growing up fast.