An Uncommon Solution to a Common Compact Framework Problem

An Uncommon Solution to a Common Compact Framework Problem

he Common Dialog API has been a solid staple in Windows development for more than a decade. In fact, not only is it a useful source of reusable code, it is a fundamental piece of the Windows look-and-feel, providing a familiar interface for users to navigate and interact with the system. As with anything so venerable, it’s not surprising that the API has evolved. But it is surprising that it has adapted so readily.

In the beginning, the Common Dialog API was unlike the classes and controls familiar to many developers today, mostly because the Windows SDK was originally geared for a C compiler. Developers could?and routinely did?import and alter resource files or hook the dialog’s window proc and intercept Windows messages to add a new control. Things got even easier when the MFC (Microsoft Foundation Classes) introduced an object-oriented approach.

Building on that familiarity, it was entirely expected that the System.Windows.Forms namespace of the .NET Framework would include a CommonDialog class and its progeny (ColorDialog, OpenFileDialog and so on)?and it does. While the .NET classes do not provide the same degree of fine turning that the older APIs do, there are still some extensibility features built in. Alas, even these more limited extensibility features do not appear in the first version of the Compact Framework on the Pocket PC. Worse, the designers of the Compact Framework made a few other choices for the Pocket PC implementation that?while perhaps sensible on their face?do not allow for the rich flexibility developers enjoy on the desktop.

Most notable is that the OpenFileDialog and the SaveFileDialog classes on the Pocket PC are restricted to the device’s My Documents directory. Although there are well intentioned reasons behind this restriction, it can sometimes become more of a hindrance than a help during development. Many applications need to browse the entire file system of the device, most commonly for files located on storage cards. But regardless of the reason for viewing other directories, if you need to tailor the user interface, you have no recourse.

While you can find a few homebrew solutions using various Web search engines, they are typically limited application solutions with no thought toward extensibility. This article covers a set of classes that not only offers an alternative for the lacking Pocket PC classes but an API specifically intended to allow you to extend the interface.

Why Reinvent the Wheel?
You could ask, “Why not just use the existing common dialog DLL and just make the appropriate P/Invoke calls?”

That’s a valid question. The answer is, “Yes, you can absolutely do that.” In fact, cursorily plumbing the System.Windows.Forms with tools such as SharpDevelop and Lutz Roeder’s Reflector provides a fair indication that Microsoft is leaning on some native calls for at least some functionality beyond normal form handling (moreso since the base CommonDialog class does not inherit from Form but instead from Component).

Creating P/Invoke wrappers does let you create dialogs that can cruise the entire file system and already have all the expected standard functionality; however, that doesn’t let you extend those dialogs through managed code. For example, if you wanted to add a new button you would need to make a number of additional unmanaged calls. Although that’s not terribly difficult, it is hardly a managed solution. Unfortunately, the problem is muddied further because OpenFileDialog and SaveFileDialog are sealed classes. So, even if you went through the trouble of writing all the unmanaged calls and wanted to package it up you would need to create a wholly new control that provided the same interface as the CommonDialog subclass you were extending. That seems like an unreasonable amount of work just to make a “simple” addition to the interface.

Designing the UncommonDialog

Figure 1. OpenFileDialog/SaveFileDialog. The figure shows the standard Open and Save dialogs for the .NET Compact Framework on the Pocket PC.

The UncommonDialog classes described in this article?provide a richer set of extensibility features than the CommonDialog classes for the Pocket PC’s Compact Framework CommonDialog implementation. The initial goal of this library is to address the shortcomings of the OpenFileDialog and SaveFileDialog classes (see Figure 1). However, these two dialogs are merely a subset of the Common Dialog API’s broader purpose of providing a constituent and coherent user interface for a wide range of tasks, such as font and color selection and some printing functions. As it stands, many of these features do not exist in the current version of the Compact Framework on the Pocket PC. The forthcoming .NET 2 Framework will address many of these design restrictions, but many will remain?specifically those on the OpenFileDialog and SaveFileDialog classes.

In addition to providing more extensibility, the UncommonDialog classes make an effort to provide a user interface similar to that of the Pocket PC’s File Explorer. OpenFileDialog and SaveFileDialog offer distinctly different looks than the standard tools of the Pocket PC. In fact, the OpenFileDialog class on the Pocket PC is downright Spartan.

The core, though not the entirety, of the UncommonDialog class API is composed of 11 classes that provide the three usable Form-based dialog controls: OpenFileBrowser, SaveFileBrowser, and FolderBrowser (see Figure 2). These three control classes derive the bulk of their functionality from the FileSystemBrowser class.

Figure 2. UncommonDialog UML Model: The UncommonDialog class API contains 11 classes that provide form-based OpenFileBrowser, SaveFileBrowser, and FolderBrowser dialog controls.

The UncommonDialog Class
This class is the base class for everything in this API and as such provides the least amount of functionality so as to provide the greatest amount of commonality. This frugal class provides three protected properties (see Table 1) and only one protected method (see Table 2).

Table 1. The table lists the UncommonDialog class’s protected properties.

Property Description
DialogMenu Returns the form’s main menu.
DialogToolbar Returns the form’s toolbar.
Panels Returns a NamedPanelCollection. This collection does not contain anything by default.

Table 2. The table lists the UncommonDialog class’s sole protected method.

Method Description
InitializeDialog This method provides an opportunity to initialize the display just prior to it being displayed. Each subclass that overrides this method should make certain to call the superclass’s implementation before adding any new functionality.

The FileSystemBrowser Class
The FileSystemBrowser is a key class in the hierarchy of the UncommonDialog API, providing both a user interface much like the Pocket PC’s File Explorer and a developer interface with ample extensibility options (see Figure 3).

Figure 3. FileSystemBrowser Snapshot: The figure shows the FileSystemBrowser running on a PocketPC.

The class provides several protected properties (see Table 3) and methods (see Table 4) that are important for use by its subclasses.

Table 3. The FileSystemBrowser class has several protected properties.

Property Description
ComparerCollection Returns the NamedComparerCollection created by the CreateComparerCollection method.
CurrentComparer Returns the IComparer currently being used to sort the display.
CurrentDirectory Returns a DirectoryInfo instance that represents the directory currently being displayed.
FileMask Returns the file mask string used to determine the current display. By default this value is “*.*”.
ListView Returns the ListView being used to display the active contents.
ListViewItemFactory Returns the IBrowserListViewItemFactory implementer created by the CreateListViewItemFactory method.
SelectedElement Returns the currently selected TaggableListViewItem.

Table 4. The table lists the FileSystemBrowser class’s protected methods.

Method Description
CreateComparerCollection The factory method for creating a NamedComparerCollection.
CreateListViewItemFactory The factory method for creating an IBrowserListViewItemFactory implementer.
DisplayDirectory This method is the core of the logic that displays the contents of the current directory. Both FilterDirectory and FilterFile are called from this method.
FileSystemContentSelected This method is called whenever the user selects something in the ListView.
FilterDirectory This method returns a Boolean determining whether or not a directory should be displayed. The base implementation checks the Hidden and System file attributes against the ShowHidden and ShowSystem properties.
FilterFile Like FilterDirectory, this method determines whether or not a file should be displayed.
OnDeleteButton This method is called when the Delete toolbar button is pressed. The base implementation will delete the currently selected directory or file.
OnNewFolderButton This method is called when the New Folder toolbar button is pressed. The base implementation will create a new folder in the current directory.
OnPropertiesButton This method is called when the Properties toolbar button is pressed and will load the PropertiesDialog form which will display the various file system data bits about the selected directory or file.
ToolbarButtonClickHandler This is the raw event handler for the toolbar. If new buttons are added this method should be overridden.

If you examined the UML model shown in Figure 2, two important classes readily become apparent: FileSystemBrowserListViewItemFactory and FileSystemComparerCollection. A class that implements the IBrowserListViewItemFactory interface configures the ListView that is central to the File Explorer-like view. The IBrowserListViewItemFactory interface defines a property for retrieving an array of ColumnHeaders and a method for creating a TaggableListViewItem, which is merely a subclass of ListViewItem that has a Tag property like its standard Framework cousin. This Tag property serves to associate System.IO.FileSystemInfo instances to be associated with each entry in the ListView. The other class, FileSystemComparerCollection, a subclass of NamedComparerCollection, provides a collection of System.Collections.IComparer implementers for sorting FileSystemInfo objects by various fields such as name, date, or size exactly as you can with the File Explorer.

The FileSystemBrowser class provides two virtual factory methods, CreateListViewItemFactory and CreateComparerCollection (noted in Table 4), so that subclasses can provide alternate implementers for customization. In addition to these two methods, there are a number of other virtual methods that let developers handle dialog control events such as the toolbar’s button-click event.

The controls of the FileSystemBrowser are packaged neatly within two panels. The navigation and the sort dropdowns are contained within a panel named “Navigation” and the ListView within a panel named “Display.” You can retrieve both panels from the NamedPanelsCollection. This contained layout makes it easy to manipulate blocks of the user interface instead of having to deal with the discrete pieces individually.

The OpenFileBrowser and SaveFileBrowser Classes
The OpenFileBrowser and SaveFileBrowser classes are meant to be drop-in replacements for the OpenFileDialog and SaveFileDialog classes, respectively. These UncommonDialog subclasses offer public properties and default functionality identical to the CommonDialog subclasses in the Compact Framework. This means that to use the UncommonDialog library a developer needs to add only a single namespace import statement (using in C# and Imports in VB.NET) and change a variable’s type.

Building an MP3 Browser
After you’ve kicked the tires on the OpenFileBrowser and SaveFileBrowser to determine that they do indeed serve well as replacements to their CommonDialog analogs, it’s time to test the extensibility features by building this useful MP3 file browser. Because the MP3 file format carries metadata in what are called “ID3 tags,” you can write code that leverages the metadata to provide extra information to help users select files.

To begin, I created a FileSystemBrowser subclass called MP3Browser, using Joel Mueller’s ID3 code (see the sidebar “Choosing an ID3Tag Library“), making it a direct subclass of FileSystemBrowser rather than OpenFileBrowser because the latter is intended for a broader sweep of capabilities?such as being able to select different file extensions. The MP3Browser should display only files with the MP3 extension, but it must be able to view and sort them based upon information stored in their ID3 tags rather than the usual file system information such as file name or size.

The MP3BrowserDialog
Creating the browser dialog itself is simple. By inheriting directly from the FileSystemBrowser class you need only implement five methods; InitializeDialog, CreateComparerCollection, CreateListViewItemFactory, Filename, and FileSystemContentSelected (see Listing 1).

CreateComparerCollection and CreateListViewItemFactory just return new instances of two classes discussed in a moment. The InitializeDialog method calls its superclass’s implementation and sets the default file mask (through the protected FileMask property inherited from FileSystemBrowser) to *.mp3. The Filename property keeps track of the user-selected MP3 file, which is set during the overridden FileSystemContentSelected method. Whenever a user selects an item in the ListView the FileSystemBrowser class calls the FileSystemContentSelected method, passing a TaggedListViewItem. The TaggedListViewItem’s Tag property contains the FileSystemInfo object which lets the browser’s logic track what MP3 file the user selects.

Figure 4. MP3Browser Snapshot: The figure shows the MP3 browser browsing the ID3 tags of the MP3 files in the Music directory.

The ID3TagListViewItemFactory Class
To accommodate the necessary changes to the ListView’s display, the MP3Browser uses a new IBrowserListViewItemFactory implementation class, called ID3TagListViewItemFactory. The CreateListViewItemFactory method (which is automatically called by the FileSystemBrowser) instantiates this class?you need only override it. This implementation defines three columns, Track, Song and Artist, which it populates by extracting the Track, SongTitle, and Artist ID3 tag fields. The class creates the columns in its constructor and stores them to a private array. The bulk of the interesting code is in the CreateListViewItem method shown in Listing 2.

As discussed previously, this method is responsible for creating a TaggableListViewItem instance using some data provided to the method in the object argument. In this case the object will be either a System.IO.DirectoryInfo or a System.IO.FileInfo since the class browses the file system. If the argument is a FileInfo object, then the browser calls Joel’s ID3Reader class to extract the ID3 tags and populate the columns (see Figure 4).

One of the most important bits of logic?stashing the FileSystemInfo object to the Tag property?occurs just before the method returns the TaggableListViewItem. This is a vital action because it provides the glue between the user interface and the file system being browsed.

The ID3TagComparerCollection
The simple ID3TagComparerCollection class inherits from NamedComparerCollection. In its constructor it loads three System.Collections.IComparer implementers. These IComparer instances expect the incoming arguments to be FileSystemInfo objects. If they are FileInfo objects the class extracts their ID3 tag and runs a text comparison against them.

After stitching all these things together you’ll have a useable MP3Browser class.

The MP3PropertiesDialog
Observant readers will notice that there is actually a sixth method in the MP3Browser code file, called OnPropertiesButton, which takes the MP3Browser class a step further overriding the properties button to display a subclass of the PropertiesDialog.

Inspecting the PropertiesDialog code, you’ll find that all its visual controls are contained within Panels in exactly the same fashion as the FileSystemBrowser. So I merely created a new Form in Visual Studio, put two tabs on it and placed some fields for the ID3 tag information on the first tab. After building the layout, I closed the designer, opened the code view and changed the inherited class to the PropertiesDialog (this functionally becomes an irreversible step since Visual Studio does not support visual inheritance for Compact Framework forms).

As you can see from the code listing there were only two methods I needed to override to achieve my goal, InitializeDialog and ProcessPropertyObject.

   protected override void InitializeDialog()   {      base.InitializeDialog();      foreach(string panelkey in this.Panels.Keys)      {         System.Windows.Forms.Panel panel = this.Panels[panelkey];         this.tabPageFileInfo.Controls.Add(panel);      }         this.textBoxSongTitle.Enabled = false;      this.textBoxArtist.Enabled = false;      this.textBoxAlbum.Enabled = false;      this.numericUpDownTrackNo.Enabled = false;   }

Leveraging the Panels collection provided by the superclass, I just moved all the panels containing the controls used to display the FileSystemInfo properties to the second tab. This is done in the InitializeDialog method; nothing very intricate or special about the effort, just the easy benefits of a little planning.

   protected override void ProcessPropertyObject()   {      base.ProcessPropertyObject();         Mueller.Utils.ID3.ID3Tag tags = null;         tags = Mueller.Utils.ID3.ID3Reader.GetFileInfo(        (System.IO.FileInfo)this.PropertyObject);      if(tags != null)      {         this.textBoxSongTitle.Text = tags.SongTitle;         this.textBoxArtist.Text = tags.Artist;         this.textBoxAlbum.Text = tags.Album;         this.numericUpDownTrackNo.Value =            int.Parse(tags.Track);      }   }
Figure 5. MP3PropertiesDialog: The dialog lets you inspect the ID3 tags and file properties of an MP3 music file.

The PropertiesDialog does its real work in the ProcessPropertyObject method. This method gets called just before the form is displayed. The class uses the object passed during construction, retrievable through the classes PropertyObject property (which is either the DirectoryInfo or FileInfo object obtained from the currently selected TaggedListViewItem at the time the user clicks the Properties button), to populate the form fields. To preserve that behavior, it calls the superclass’s ProcessPropertyObject method immediately and then reads the ID3 tags from what is assumed to be a FileInfo object. Figure 5 shows the PropertiesDialog.

This high-speed tour through the still emerging UncommonDialog API demonstrates not only a drop-in replacement for some of the CommonDialog subclasses but also an extensible system meant to keep pace with the needs of more configurable systems. The MP3Browser demonstration project shows the kind of flexibility that you can easily extend to browser subclasses for viewing FTP or WebDAV servers, or?with a little more effort?adapted to work with LDAP hierarchies.



Share the Post:
5G Innovations

GPU-Accelerated 5G in Japan

NTT DOCOMO, a global telecommunications giant, is set to break new ground in the industry as it prepares to launch a GPU-accelerated 5G network in

AI Ethics

AI Journalism: Balancing Integrity and Innovation

An op-ed, produced using Microsoft’s Bing Chat AI software, recently appeared in the St. Louis Post-Dispatch, discussing the potential concerns surrounding the employment of artificial

Savings Extravaganza

Big Deal Days Extravaganza

The highly awaited Big Deal Days event for October 2023 is nearly here, scheduled for the 10th and 11th. Similar to the previous year, this

5G Innovations

GPU-Accelerated 5G in Japan

NTT DOCOMO, a global telecommunications giant, is set to break new ground in the industry as it prepares to launch a GPU-accelerated 5G network in Japan. This innovative approach will

AI Ethics

AI Journalism: Balancing Integrity and Innovation

An op-ed, produced using Microsoft’s Bing Chat AI software, recently appeared in the St. Louis Post-Dispatch, discussing the potential concerns surrounding the employment of artificial intelligence (AI) in journalism. These

Savings Extravaganza

Big Deal Days Extravaganza

The highly awaited Big Deal Days event for October 2023 is nearly here, scheduled for the 10th and 11th. Similar to the previous year, this autumn sale has already created

Cisco Splunk Deal

Cisco Splunk Deal Sparks Tech Acquisition Frenzy

Cisco’s recent massive purchase of Splunk, an AI-powered cybersecurity firm, for $28 billion signals a potential boost in tech deals after a year of subdued mergers and acquisitions in the

Iran Drone Expansion

Iran’s Jet-Propelled Drone Reshapes Power Balance

Iran has recently unveiled a jet-propelled variant of its Shahed series drone, marking a significant advancement in the nation’s drone technology. The new drone is poised to reshape the regional

Solar Geoengineering

Did the Overshoot Commission Shoot Down Geoengineering?

The Overshoot Commission has recently released a comprehensive report that discusses the controversial topic of Solar Geoengineering, also known as Solar Radiation Modification (SRM). The Commission’s primary objective is to

Remote Learning

Revolutionizing Remote Learning for Success

School districts are preparing to reveal a substantial technological upgrade designed to significantly improve remote learning experiences for both educators and students amid the ongoing pandemic. This major investment, which

Revolutionary SABERS Transforming

SABERS Batteries Transforming Industries

Scientists John Connell and Yi Lin from NASA’s Solid-state Architecture Batteries for Enhanced Rechargeability and Safety (SABERS) project are working on experimental solid-state battery packs that could dramatically change the

Build a Website

How Much Does It Cost to Build a Website?

Are you wondering how much it costs to build a website? The approximated cost is based on several factors, including which add-ons and platforms you choose. For example, a self-hosted

Battery Investments

Battery Startups Attract Billion-Dollar Investments

In recent times, battery startups have experienced a significant boost in investments, with three businesses obtaining over $1 billion in funding within the last month. French company Verkor amassed $2.1

Copilot Revolution

Microsoft Copilot: A Suit of AI Features

Microsoft’s latest offering, Microsoft Copilot, aims to revolutionize the way we interact with technology. By integrating various AI capabilities, this all-in-one tool provides users with an improved experience that not

AI Girlfriend Craze

AI Girlfriend Craze Threatens Relationships

The surge in virtual AI girlfriends’ popularity is playing a role in the escalating issue of loneliness among young males, and this could have serious repercussions for America’s future. A

AIOps Innovations

Senser is Changing AIOps

Senser, an AIOps platform based in Tel Aviv, has introduced its groundbreaking AI-powered observability solution to support developers and operations teams in promptly pinpointing the root causes of service disruptions

Bebop Charging Stations

Check Out The New Bebob Battery Charging Stations

Bebob has introduced new 4- and 8-channel battery charging stations primarily aimed at rental companies, providing a convenient solution for clients with a large quantity of batteries. These wall-mountable and

Malyasian Networks

Malaysia’s Dual 5G Network Growth

On Wednesday, Malaysia’s Prime Minister Anwar Ibrahim announced the country’s plan to implement a dual 5G network strategy. This move is designed to achieve a more equitable incorporation of both

Advanced Drones Race

Pentagon’s Bold Race for Advanced Drones

The Pentagon has recently unveiled its ambitious strategy to acquire thousands of sophisticated drones within the next two years. This decision comes in response to Russia’s rapid utilization of airborne

Important Updates

You Need to See the New Microsoft Updates

Microsoft has recently announced a series of new features and updates across their applications, including Outlook, Microsoft Teams, and SharePoint. These new developments are centered around improving user experience, streamlining

Price Wars

Inside Hyundai and Kia’s Price Wars

South Korean automakers Hyundai and Kia are cutting the prices on a number of their electric vehicles (EVs) in response to growing price competition within the South Korean market. Many

Solar Frenzy Surprises

Solar Subsidy in Germany Causes Frenzy

In a shocking turn of events, the German national KfW bank was forced to discontinue its home solar power subsidy program for charging electric vehicles (EVs) after just one day,

Electric Spare

Electric Cars Ditch Spare Tires for Efficiency

Ira Newlander from West Los Angeles is thinking about trading in his old Ford Explorer for a contemporary hybrid or electric vehicle. However, he has observed that the majority of

Solar Geoengineering Impacts

Unraveling Solar Geoengineering’s Hidden Impacts

As we continue to face the repercussions of climate change, scientists and experts seek innovative ways to mitigate its impacts. Solar geoengineering (SG), a technique involving the distribution of aerosols

Razer Discount

Unbelievable Razer Blade 17 Discount

On September 24, 2023, it was reported that Razer, a popular brand in the premium gaming laptop industry, is offering an exceptional deal on their Razer Blade 17 model. Typically

Innovation Ignition

New Fintech Innovation Ignites Change

The fintech sector continues to attract substantial interest, as demonstrated by a dedicated fintech stage at a recent event featuring panel discussions and informal conversations with industry professionals. The gathering,

Import Easing

Easing Import Rules for Big Tech

India has chosen to ease its proposed restrictions on imports of laptops, tablets, and other IT hardware, allowing manufacturers like Apple Inc., HP Inc., and Dell Technologies Inc. more time