Archive for the ‘User Interface’ Category

Add Cut/Copy/Paste functionality to a Textbox

Tuesday, October 2nd, 2007

Earlier I discussed how you could manually get the software keyboard (SIP) to display whenever a TextBox control gained focus. There was potentially a lot of event handlers to write, two for every control on a form. Today I will show you an alternative approach that utilises less code but also has some additional benefits.

A common thing I do while testing new Windows Mobile applications, is to tap-and-hold on a text field. Very well behaved applications should popup a context sensitive menu containing cut/copy/paste style options for the current control. Surprisingly, very few applications actually pass this test, even though it is a feature that has been built into the operating system for a while.

Within Windows CE the SIPPREF control can be used to automatically implement default input panel behavior for a dialog. It provides the following features:

  • The Input Panel is automatically shown/hidden as controls gain and loose focus.
  • Edit controls have an automatic context menu with Cut, Copy, Paste type options.
  • The SIP state is remembered if the user switches to another application and later returns to this form.

In my mind this has three advantages over the process I previously discussed.

  1. You add the SIPPREF control once and it automatically hooks up event handlers for each of your controls. With the manual event handler approach it’s easy to add a new control and forget to hook up the events required to handle the SIP.
  2. You get free localisation. Although you could create a custom context menu for cut/copy/paste, you would need to localise the text into multiple languages yourself (if you are concerned with true internalisation that is) and it’s another thing thing to hook up for each control.
  3. You get standardised behavior. By using functionality provided by the operating system you are ensuring that your application has a natural and expected behavior to it. If the platform ever changes the conventions of SIP usage, your application will automatically be updated.

For the rest of this blog entry I will discuss how to go about utilising the SIPPREF control within your application. I have split my discussion into two sections. The first section will be of interest to native developers developing in C or C++, while the second section is intended for .NET Compact Framework developers.

Each section contains a small example application which demonstrates the behaviour of the SIPPREF control within the respective environment. When you run the sample applications you will notice that the SIP does not popup up when you click within a text box. And a tap-and-hold operation yields nothing. This behaviour changes when a SIPPREF control is added to the dialog, which can be achieved by clicking the sole button.

Native Developers

[Download sipprefcontrolnativeexample.zip 16KB]

In order to use the SIPPREF control we must first request the operating system to register the SIPPREF window class. We do this by calling the SHInitExtraControls function. This step only needs to be done once, so is typically done during your application’s start up code. It is very easy to call, as the following example demonstrates:

#include <aygshell.h>
 
SHInitExtraControls();

Since SHInitExtraControls lives within aygshell.dll, we also need to modify our project settings to link with aygshell.lib, otherwise the linker will complain that it can not find the SHInitExtraControls function.

Once we have registered the SIPPREF window class, we simply create a SIPPREF control as a child of our dialog. When the SIPPREF control is created it will enumerate all sibling controls and subclass them in order to provide the default SIP handling behaviour. The SIPPREF control must be the last control added to your dialog, as any controls added after the SIPPREF control will not be present when the SIPPREF control enumerates its siblings, and hence will not be subclassed to provide the proper SIP handling.

If dynamically creating the SIPPREF control, a good place to do this is within the WM_CREATE or WM_INITDIALOG message handler, as the following code sample demonstrates:

case WM_INITDIALOG:
  // Create a SIPPREF control to handle the SIP. This
  // assumes 'hDlg' is the HWND of the dialog.
  CreateWindow(WC_SIPPREF, L"", WS_CHILD,
       0,  0, 0, 0, hDlg, NULL, NULL, NULL);

As an alternative to dynamically creating the SIPPREF control, we can place the control within our dialog resource by adding the following control definition to the end of a dialog within the project’s *.rc file.

CONTROL  "",-1,WC_SIPPREF, NOT WS_VISIBLE,-10,-10,5,5

Depending upon your developer environment you may even be able to do this entirely from within the Resource Editor GUI. For example within Visual Studio 2005 you could drag the “State of Input Panel Control” from the Toolbox onto your form to cause a SIPPREF control to be added.

sip-toolbox.png

.NET Compact Framework Developers

[Download sipprefcontrolexample.zip 16KB]

The process of using the SIPPREF control for a .NET Compact Framework application is fairly similar to that of a Native application. Since the .NET Compact Framework does not natively support the use of dialog templates, we must use the CreateWindow approach to create a SIPPREF control dynamically at runtime.

The first step is to declare a number of PInvoke method declarations for the various operating system APIs we need to call.

using System.Runtime.InteropServices;
 
[DllImport("aygshell.dll")]
private static extern int SHInitExtraControls();
 
[DllImport("coredll.dll")]
private static extern IntPtr CreateWindowEx(
  uint dwExStyle,
  string lpClassName,
  string lpWindowName,
  uint dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  IntPtr hWndParent,
  IntPtr hMenu,
  IntPtr hInstance,
  IntPtr lpParam);
 
  private static readonly string WC_SIPPREF = "SIPPREF";
  private static readonly uint WS_CHILD = 0x40000000;

One interesting fact is that we PInvoke a function called CreateWindowEx, while the native example above called CreateWindow. If you dig deeper into the Window Header files you will notice that CreateWindow is actually a macro which expands into a call to CreateWindowEx. At the operating system level the CreateWindow function doesn’t actually exist.

With this boiler plate code out of the way, the solution is very similar to the native one…

protected override void OnLoad()
{
     // Initialise the extra controls library
     SHInitExtraControls();
 
     // Create our SIPPREF control which will enumerate all existing
     // controls created by the InitializeControl() call.
     IntPtr hWnd = CreateWindowEx(0, WC_SIPPREF, "", WS_CHILD,
          0, 0, 0, 0, this.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}

In the above example we simply create the SIPPREF control within the OnLoad method of our form. Within the downloadable sample project I have wrapped up this code into a static method called SIPPref.Enable(Form f) to enable to it easily be reused between forms.

Hopefully today I have shown you that having knowledge of the underlying operating system is still a useful skill to have for .NET Compact Framework developers. Knowing the features provided by the operating system can allow you to add some neat functionality to your applications with little additional effort on your behave.

Creating non full screen forms and custom MessageBoxes

Monday, October 1st, 2007

A screenshot of a custom message box form which is not full screen.Every now and then someone asks how to create a .NET Compact Framework form which does not cover the fullscreen. Here is my solution to this problem.

This solution is built upon details discussed by other bloggers, including:

The trick is to set the form’s FormBorderStyle property to None. This disables the .NET Compact Framework’s built in functionality which forces a form to become fullscreen (on Windows Mobile devices), but also has the side effect of removing the border around the edge of the form. We can add the border (and a caption) back via the use of some PInvoke calls into the native operating system.

Points of interest

I decided to create my solution as two classes which are designed to be reusable within your own applications. One class enables the non full screen functionality, while the other provides an implementation for a common reason why non full screen forms are requested. These classes are as follows:

  1. NonFullScreenForm – a base class which you can use instead of Form. This base class allows you to have a form which does not cover the entire screen, and will optionally automatically center the form in the middle of the screen.
  2. MessageBoxForm – this is a subclass of NonFullScreenForm which provides a static method called Show. This method behaves in a similiar way to the standard MessageBox.Show API, with a few extensions such as the ability to use custom buttons.

Example Application

[Download nonfullscreendemo.ZIP 32Kb]

The example application available for download demonstrates the use of the NonFullScreenForm and MessageBoxForm classes via a series of buttons.

The first two buttons compare the behaviour of the standard MessageBox.Show API against our custom MessageBoxForm implementation for a number of message box styles. You will notice that the look and feel of our custom message boxes are similiar, but often have a slightly different layout.

The button labeled “Auto Centered Form” demonstrates the effect of setting NonFullScreenForm’s CenterFormOnScreen property to True. Whenever you tap the “Expand” or “Collapse” buttons the form changes size, and the NonFullScreenForm base class automatically changes the location of the form to ensure it is centered at all times. It will even re-center the form when the device switches between landscape and portrait modes.

How to use the NonFullScreenForm class

To use the NonFullScreenForm class within your own applications follow these steps:

  1. Add NonFullScreenForm.cs to your project.
  2. Set the FormBorderStyle property of your form to None.
  3. Set the Size and Location properties of your form to the desired size and position on the screen.
  4. View your form’s source code and change the form to derive from NonFullScreenForm instead of Form.
  5. If you want your form automatically centered on the screen set the CenterFormOnScreen property to true.
  6. If you don’t want an [OK] button in the caption, set the ControlBox property to false.

There are a number of areas where these custom controls could be improved. MessageBoxForm’s compatability could be improved. It does not support displaying an icon within the MessageBox at present for instance. There is also a slight flickering on the navbar (the bar at the top of the device which contains the start menu etc) when a non full screen dialog is created which would be nice to eventually remove. This is caused by the .NET Compact Framework dispaying the form before we have had a chance to change it’s window style to include a caption.

These controls were quickly put together to demonstrate what could be possible with a little bit of work. If anyone is interested in collaborating to improve these controls, I would be keen to hear from them.

Creating a Tab Control for the Smartphone

Saturday, September 29th, 2007

Screenshot of sample application demonstrating the tab control I developed for Windows Mobile Smartphone devicesThe .NET Compact Framework does not support a Tab Control when targeting a Windows Mobile Smartphone device. Today I present a sample custom control designed to provide a suitable replacement for System.Windows.Forms.TabControl when you are building a Smartphone application.

I am not sure using such a control is good from a usability perspective, but it has been asked for enough times within the developer community, that this time I decided to provide a working solution. This was especially true once I determined the custom tab control would also provide some benefits for Pocket PC developers.

My development background was originally in the native world writing applications in C and C++. As such I know the raw Win32 APIs provided by the Windows Mobile operating system pretty well. The smartphone OS actually provides the standard Commctrl.h Tab Control, however the .NET Compact Framework has decided not to expose this functionality. So this custom control simply uses quite a lot of Platform Invoke calls to wrap up the native tab control provided by the operating system in a .NET Compact Framework friendly manor.

Benefits of this control

  • Works on both Smartphone and Pocket PC devices.
  • Allows tabs to have an optional bitmap displayed beside the text.
  • Exposes a SelectedIndexChanging event which allows the programmer to cancel a tab change if the application logic desires.

Sample Application

A sample application which runs on both Pocket PC and Smartphone devices is available for download. This download also contains the file SmartphoneTabControl.cs which contains the source code for the custom control itself.

[Download smartphonetabcontrol.zip 48KB]

The sample application has three tabs and demonstrates how you can navigate the tabs via the left and right arrow keys. Once you have selected the third tab, you can use the up and down arrow keys to select the various textbox controls, and return to the tab control to select another tab.

Another neat feature demonstrated in the sample application is a way to have an animated icon displayed on a tab. This may be useful for a tabbed interface where a tab is displaying the results of an asynchronous or lengthy operation (such as a file download). The tab’s icon could be animated while the operation is still in progress, allowing the user to determine the state of the operation with a quick glance.

How to use the control

  1. Add SmartphoneTabControl.cs to your solution.
  2. Compile your project (needed to get the control into your toolbox).
  3. Drag a SmartphoneTabControl from your toolbox onto your form.
  4. Dock the tab control to the bottom and make it 26 pixels high.
  5. Add one or more Panel controls to your form (one for each tab page) and set the DockStyle property of each one to ‘Fill’.
  6. Populate the panels with the controls you want visible on each tab.
  7. Within your form’s constructor call the SmartphoneTabControl’s AddTab() method to create each tab, passing in the name of the tab, an optional image, and the panel which contains it’s controls.

There are a couple of outstanding bugs/missing features with this control. The biggest being the lack of design time support and device resolution independance. This control was quickly put together to demonstrate what could be possible with a little bit of work. If anyone is interested in collaborating to improve this control, I would be keen to hear from them.

Programmatically create and display Notifications

Thursday, August 2nd, 2007

Screenshot showing an example popup notification on a Windows Mobile 6 Professional deviceThe Windows Mobile operating system provides a Notifications feature which can be utilised to display prompts to the user in the form of toast or popup balloons (depending upon operating system version) even when your application is running in the background. These are ideal for when your application must inform the user that background tasks have completed, or that particular actions must be performed. This blog entry discusses how you can utilise notifications within your own applications.

Supported Platforms
Notifications are only supported on Windows Mobile Professional or Classic (i.e. Pocket PC) devices, they are not supported on Windows Mobile Standard (i.e. Smartphone) devices. If you develop a Compact Framework application which uses notifications, the application will compile when you target a Windows Mobile Standard device, but will cause a NotSupportedException when the application is ran on the device.

To utilise the Microsoft.WindowsCE.Forms.Notification class you must add a reference to the Microsoft.WindowsCE.Forms.dll assembly.

One of the easiest ways to obtain this reference, and to configure your notification is to drag a “Notification” component from the Toolbox within Visual Studio 2005 (it is located within the Device Components category). Doing this will automatically added the needed reference to your project, and allow you to configure the notification’s properties graphically via the Properties window.

Notification Properties
The notification class has a number of properties which control the look and feel of the notification balloon. These properties are as follows:

  • Caption – the text displayed in the caption bar at the top of the notification balloon.
  • Text – a string containing the HTML content to display in the main part of the notification popup. This enables you to use formatting, and different colours within your notifications.
  • Critical – a boolean flag, if set to true this indicates that the notification is of urgent importance. This has the effect of using a different colour border around the edge of the notification.
  • Icon – The icon to display on the nav bar for the notification. The user can tap on this icon to display a hidden notification, so it should be representative of the meaning of the notification.
  • InitialDuration – the number of seconds the notification should appear on the screen when initially made visible. After this duration has expired the notification will hide itself, and the user will have to tap on the icon on the nav bar to make it re-appear. If this value is set to zero the popup notification is not displayed, instead going straight to the icon on the nav bar.
  • Visible – setting the Visible property to true, will make the notification balloon appear on the screen.

Displaying a notification
To display a notification to the user is as simple as creating an instance of the Notification class, setting up the properties for the desired effect, and then finally setting the Visible property to true to make the notification visible to the user. This is demonstrated in the following sample:

using Microsoft.WindowsCE.Forms;
 
private Notification n = null;
 
private void button1_Click(object sender, EventArgs e)
{
  // Create an instance of the notification class and configure
  // its properties for the desired effect.
  n = new Notification();
  n.Caption = "Hello World!";
  n.Text = "<b>This</b> is a <u>sample</u> notification!";
  n.Critical = false;
  n.Icon = Properties.Resources.NotificationIcon;
 
  // Finally to make the notification appear on screen
  // set the Visible property to true.
  n.Visible = true;
}

One important thing to notice is that we have not used a local variable within the button1_Click method to hold the Notification we are displaying to the user. The reason for this has to do with the CLR and its Garbage Collection behavior. Although the code may work if you use a local variable, it is not guaranteed and will potentially lead to unpredictable behavior (more on this in a later section).

The only property which deserves further discussion is the Icon one. You can store an icon in a number of ways. Perhaps the easiest way to store an icon in your executable is to use the Resources.resx file the Visual Studio 2005 project wizard will have created for you. The following screenshot demonstrates where you can find this file within solution explorer. If you open the file you can add new icon(s) into it, and these icons will be accessible via strongly typed properties within the Properties.Resources class, as demonstrated by the code sample above.

Screenshot of Visual Studio 2005 demonstrating how to find the Resources.resx file to include the icon resource

Hiding a notification
There are two different ways you can remove a notification which is visible on the screen.

You can simply set the Visible property to false, as the following example demonstrates:

// Using this approach to hide a notification will allow you
// to re-display it by changing the Visible property back to true.
n.Visible = false;

This has the benefit that you can decide to re-display the notification, by simply resetting the Visible property back to true. You can change the Visible property as many times as you like.

The alternative approach is to call the Dispose method of the Notification class, as the following example demonstrates:

// Using this approach will hide the notification but won't
// allow you to re-display it without creating a new instance
// of the Notification class.
n.Dispose();

Once you have done this you will not be able to display the notification again, without creating a new instance of the Notification class.

Previously we mentioned that you should not use a local variable to reference your Notification object. This last code sample demonstrates the reason why. If you had stored your notification in a local variable within the button1_Click method, the garbage collector would detect your variable as potential garbage when the method completed. If a garbage collection occurred, and decided to collect this reference, the garbage collector would call the Dispose method on the notification, which would remove it from the screen. By keeping a reference to the notification “alive” for the life time of the form (by using a member variable to reference it) the garbage collector will not be able to dispose of it until the form is closed.

Detecting when the notification is hidden
The notification class has a BallonChanged event which fires whenever the notification balloon is made visible, or hidden.

The following example, demonstrates how you can listen to this event, in order to perform a task when the popup balloon is hidden:

Notification n = new Notification();
// configure the notification properties...
n.BallonChanged += new BallonChangedEventHandler(n_BallonChanged);
 
void n_BalloonChanged(object sender, BalloonChangedEventArgs e)
{
  // The Visible property indicates the current state of the
  // popup notification balloon
  if (e.Visible == false)
  {
    // If the balloon has now been hidden, display a message box
    // to the user.
    MessageBox.Show("The balloon has been closed", "Status");
  }
}

Sample Application
Screenshot of sample applicationA sample application is available for download, which demonstrates the use of the Notification class. It enables you to experiment with the various properties of the notification class, and see how they alter a notification.

There is one member of the Notification class which we have not discussed in this blog entry. This is the ResponseSubmitted event which can be used to process feedback provided by the user when they dismiss the popup notification. For example in the HTML text of a notification, you could create a couple of radio buttons, and a text field. By handling the ResponseSubmitted event you can determine what values the user has entered and use them to alter the behavior of your application. Covering how to utilise the ResponseSubmitted event to process HTML based forms will be the topic of a future blog entry.

Provide Help for an application

Friday, July 20th, 2007

Yesterday I provided a tip about using the context sensitive help feature within Windows Mobile. I finished the post with a gotcha, mentioning that it worked in few third party applications. This was due to the feature needing to be explicitly handled by the application developer. This blog entry is designed to discuss how .NET Compact Framework developers can implement integrated help within their own applications.

Integrating help into your application
Help within Windows Mobile is implemented by an application called peghelp.exe. This application is essentially a host for a web browser control which renders an HTML based help file.

There is typically one HTML help file per application. A special structure is used within the HTML file to determine where to split topics.

As a demonstration of how this works you may like to use the run dialog tip mentioned yesterday to run “peghelp \windows\calc.htm#Main_Contents”. This will view the help file associated with the built in calculator application.

Within the .NET Compact Framework the System.Windows.Forms.Help class helps wrap up this functionality and hide the specifics of launching peghelp.exe.

The ShowHelp method will display a specified topic within a help file. It can be invoked from within a button click event handler reasonably easily, as the following example demonstrates:

private void button1_Click(object sender, EventArgs e) 
  { 
  Help.ShowHelp(this, @"\windows\calc.htm#Main_Contents"); 
  }

Notice the ‘#’ character which seperates the path of the HTML help file and the name of the topic.

The first code sample is ideal for launching help from a button or menu item within our application. To launch your help by using the context sensitive help feature within the Windows Start Menu you need to listen to the form’s HelpRequested event as shown below.

private void Form1_HelpRequested(object sender, HelpEventArgs hlpevent) 
{ 
  Help.ShowHelp(this, @"\windows\calc.htm#pptskusecalculator"); 
}

By using unique topic names within the event handler associated with each form, you can obtain context sensitive help. In an advanced application you may even place conditional logic within your HelpRequested event handler. This enables you to display different help topics, depending upon the state of your user interface.

Creating your own help file
The help file for your application is a simple HTML file. However there are a couple of special tags you must utilise, in order for the help application to be able to split up your single file into multiple topics.

To create your first topic within an HTML help file, insert the following elements within the <body> element of the file.

<!-- PegHelp --> 
<a name="SomeTopic" title="SomeTopic" />    
 
.... HTML contents of topic goes here ....

The value of the name attribute (in this case set to “SomeTopic”) is the unique name for the topic, and is the value you should use to link to this topic.

The only special topic name that you should use is “Main_Contents” which should point to a topic which is suitable for use as a table of contents. Other than this topic name, you are free to use what ever names suit you.

To create additional topics, simply repeat this structure as many times as required. After the last topic it is very important to place another <!– PegHelp –> comment to mark the end of the help file. It is a common mistake for this comment to be missed and this has the effect of hiding the last topic.

Links between topics
Typically you will want to refer to other topics from within a topic. For example, at the bottom of each topic you may want to have a “see also” section, which lists other relevant topics.

To refer to another topic within your help file you use standard HTML anchor functionality, referring to the anchor name of the topic you want to jump to. This syntax is shown below, and is basically the path of your help file and the desired topic name seperated by a ‘#’ character.

<a href="MyHelpFile.htm#main_contents">Table Of Contents</a>

Development Tips
The parser used to break up a single file into multiple topics is not case sensitive, however it is sensitive to whitespace and changes in the format of the HTML elements. My recommendation is to utilise the same formatting of the <A NAME=”…”> and <!– PegHelp –> elements as shown in the examples in this blog entry. If you find that a topic is missing, or the content of more than one topic have become merged, double check that you have not accidently inserted additional whitespace between attributes etc.

When creating your help file you are most likely going to be using a desktop web browser which will show all your topics in one large page. When doing this it can become tricky to determine where one topic ends and another begins.

There is a special trick which will help resolve this issue. If you place an <hr> element immediately after each <!– PegHelp –> comment you will get nice divider lines separating each topic when you view your HTML help file within a desktop web-browser. However when you view the help file from within the Windows Mobile Help application they will have been removed.

Adding Keyword Search
Screen-shot showing search results including topics within the HTML help fileWithin the <head> element of your help file it can be handy to list a series of help topics and their matching keywords by using the <keyword> element. These keyword definitions are utilised by the Windows Mobile Find application when the user searches for help on a given topic (i.e. the find application does not search through your entire help file, it relies upon your explicitly listing all relevant keywords).

Some example keyword enteries may look like the following two example entries.

<keyword value="Puzzle;Games" title="Tetris 2000" href="tetris.htm#main_contents" />
<keyword value="High Score;Internet" title="Tetris 2000 High Score" href="tetris.htm#highscore"  />

The value element contains a list of keywords separated by semi colons, while the title element contains the title which will be displayed within the Find application when a match is found. Finally the href element contains the topic reference of the topic which should be displayed when a matching keyword is found.

Including Images
Images are displayed within the HTML help file using standard <img> HTML elements. However there are a couple of limitations to be aware of. The documentation on MSDN states that all images must be bitmaps with the *.2bp file extension. I believe that this document is purely a historical reference. I have had no problem using standard bitmaps with the *.bmp file extension, and I notice some of the included system help files do the same. You can not however utilise other image file formats, such as JPEGs or PNGs from within your help file.

URLs used to reference images are also relative to the \Windows directory, not the folder your HTML help file is located within.

Deploying your custom help file
Realistically your HTML help file must be located within the \windows directory. The help application can have problems if you place your help file in other locations, due to the need to use hardcoded file paths to refer to additional topics and images. These hard coded references will break if the user chooses to install your application in a different location, or your application is installed on a localised version of Windows Mobile (which will have different names for folders such as “My Documents”).

If you want the help file to show up in the main list of help files you should also place a shortcut link to your help file within the \windows\help folder. On a Windows Mobile 5.0 device this means that the help file will be accessable by selecting the “Help for Added Programs” entry within the help application’s table of contents.

If you are using a Smart Device CAB Project within Visual Studio 2005 to build your application cab you can include your help file within the CAB file by using the following procedure:

  1. Right click on your deployment project within the Solution Explorer and select “File System” from the “View” submenu.
  2. On the “File System on Target Machine” entry on the left hand side of the window, right click and select “Windows Folder” from the “Add Special Folder” submenu.
  3. Right click on the newly created “Windows Folder” directory and select “Folder” from the “Add” submenu.
  4. Type in “Help” and press enter
  5. Click on “Windows Folder” to select it
  6. On the right side of the window right click and select “File…” from the “Add” submenu
  7. Browse to your HTML help file and click “Open”
  8. Right click on the help file and select “Create Shortcut to ….”
  9. Rename the shortcut to remove the “shortcut to…” prefix
  10. Drag the shortcut to the “Help” subdirectory created above

Example Application
An example application which demonstrates how to create a properly formatted HTML help file, and launch it from a .NET Compact Framework application is available for download.

I have included the source code for the application, as well as a pre-built cab file. I would suggest you install the CAB file onto your device and have a play around with how it integrates the application’s help within the help application.

As a starter, try searching for “transport” or “chris” within the Find utility (you can find this within the “Programs” start menu option) and see how this produces links to the help file installed along with the application.

Revision History
26 July 2007 – updated the example application to include examples of using images within help topics in response to a recent forum thread.

Manage soft input panel (SIP)

Sunday, July 15th, 2007

One final finishing touch to Windows Mobile applications is the proper handling of the Software-based Input Panel (SIP), this can help differentiate your application, and thus your company as one which truely understands the Windows Mobile platform.

The software-based input panel (also known as the popup or software keyboard) allows touch-screen enabled devices that do not have a hardware keyboard to simulate keyboard input by using an onscreen keyboard.

The SIP is a common piece of UI, which enables the use of one or more Input Methods (IMs). Standard Input Methods include Keyboard, Transcriber and Block Recognizer, but additional OEM specific IMs may be included on a given device.

This architecture is extendable, and third parties can create their own IMs by implementing a COM object, as outlined in the book Prorgraming Microsoft Windows CE, Second Edition (see the free sample chapter for step by step instructions). One interesting third party input panel is the Smilies Input Panel by Yin-See Tan which is designed to help users enter similies into MSN messenger.

Tight integration of the SIP within your application typically boils down to handling two scenarios well:

  • Automatically displaying the SIP when keyboard focus passes to a control which requires keyboard data entry.
  • Ensuring all controls are accessible when the SIP is visible.

SIP support within the .NET Compact Framework
Within the .NET Compact Framework the software-based input panel is wrapped up by the Microsoft.WindowsCE.Forms.InputPanel class, which is present in the Microsoft.WindowsCE.Forms.dll assembly.

In order to interact with the software-based input panel, the user can drop the InputPanel component from the Visual Studio toolbox onto a form. A reference to the Microsoft.WindowsCE.Forms.dll assembly will be added automatically to your project.

Most applications utilising the InputPanel component will make use of the following four members of the class.

  • Enabled – A boolean property. If true the SIP is visible (on the screen), if false the SIP is hidden.
  • EnabledChanged – An event which fires whenever the Enabled property changes value.
  • Bounds – A rectangle detailing the amount of screen real estate the current input method occupies.
  • VisibleDesktop – A rectangle detailing the maximum size the current screen real estate the form can cover without being partially covered by the SIP.

Automatic SIP Popup
Within the .NET Compact Framework the easiest way to automatically display the Input Panel is to explicitly enable and disable the input panel whenever a control which requires keyboard focus is activated.

private TextBox txtUserName;
 
private void Form1_Load(object sender, EventArgs e)
{
  txtUserName.GotFocus += txtUserName_GotFocus;
  txtUserName.LostFocus += txtUserName_LostFocus;
}
 
private void txtUserName_GotFocus(object sender, EventArgs e) 
{ 
   // Show the input panel
   inputPanel1.Enabled = true; 
}   
 
private void txtUserName_LostFocus(object sender, EventArgs e) 
{ 
  // Hide the input panel
  inputPanel1.Enabled = false; 
}

Notice: Usually the event hook up code shown within the Form1_Load event handler would occur within the designer generated code. It is only shown here to aid in understanding how this sample code functions.

Dynamic Dialog Layout
Since the SIP is displayed on screen it covers part of your form when visible and potentially makes some of your controls inaccessable. A quality application will alter the layout of its form when the SIP becomes visible to ensure all controls are accessible at all times. There are numerious techniques that can be utilised to achieve this goal.

Technique One:
One approach is to listen to the InputPanel’s EnabledChanged event. This event will trigger whenever the SIP’s visibility changes. Within the event handler we can move controls around to ensure that they are visible within the current space available to the form.

private void InputPanel1_EnabledChanged(object sender, EventArgs e) 
{ 
  int y;
 
  if (inputPanel1.Enabled)
    // SIP visible - position label just above the area covered by the input panel  
    y = Height - inputPanel1.Bounds.Height;
  else
    // SIP not visible - position label just above bottom of form
    y = Height;
 
  // Calculate the position of the top of the label
  y = y - lblMessage.Height;
 
  lblMessage.Location = new Point(0, y);
}

This approach is the most flexiable, but it can become tricky depending upon the number of controls which need to be moved around. Coordinate calculations are never fun, especially when multiple device resolutions etc have to be taken into account.

Technique two:
Another technique which doesn’t involve explict coordinate calculations is to take advantage of the Docking and Anchoring functionality present with .NET Compact Framework v2.0.

The trick is to dock a control to the bottom of the form, and to resize this control’s height to match the current height of the SIP. This has the effect of pushing the rest of the content docked to the bottom of the form to be above the SIP.

This approach is shown in the following example:

private void InputPanel1_EnabledChanged(object sender, EventArgs e) 
{ 
  // Resize the panel docked to the bottom of the form to be
  // the same height as the SIP. This moves other controls also
  // docked to the bottom of the form to be above the area covered
  // by the SIP.
  SuspendLayout();
  panelSIP.Visible = inputPanel1.Enabled;
  panelSIP.Height = inputPanel.Bounds.Height;
  ResumeLayout();
}

This approach can also be extended to cope with larger forms, where the only real solution is to place a vertical scroll bar onto the form. If all the controls are placed onto a panel, you can configure the panel by setting the following properties:

  • AutoScroll – true
  • Dock – fill

With these properties set, you will find a vertical scrollbar automatically appears when required (due to the SIP becomming visible).

An added finishing touch to this technique is to ensure that any controls on the right hand side of the form has the Anchor property set to “Right”. This ensures that the controls are not obsecured by the vertical scrollbar when it is present.

Selecting Input Methods
The InputPanel component can also be used to enumerate a list of available Input Methods, and to determine which one is currently active.

// List the name and class id of each input method
// registered on this device
foreach (InputMethod im in inputPanel1.InputMethods)
{
  MessageBox.Show(im.Name, im.Clsid.ToString());
}
 
// Display the name of the currently active input method
InputMethod currentIM = inputPanel1.CurrentInputMethod;
MessageBox.Show(im.Name, "Current Input Method");

The InputMethod class is a simple key, value pair containing the name of the Input Method (a string shown in the SIP popup menu), and the matching class id. Class identifiers are a COM specific concept which uniquely identify different types of object, and since the software-based input panel architecture is COM based, each input method can be uniquly referred to by its clsid value.

Code Sample
A sample project which demonstrates all the techniques discussed in this article is available for download, and should help clarify the behaviour of the InputPanel control.

VB.NET and InputBox()
Recently a software-based input panel related question came up within an online forum I participate in. As part of answering the question I learnt of a VB.NET function called InputBox. InputBox is a function which provides a basic data entry mechanism, similar to how MsgBox displays simple messages to the user.

It turns out that Microsoft’s implementation of InputBox does not deal with dynamically moving the OK and Cancel buttons around to ensure that they are visible if the software-based input panel is visible. It also does not look too nice on VGA resolution devices.

I have written a replacement InputBox implementation which resolves these issues. My new and improved InputBox, including a sample project is available for download. I hope this control is of use to those wising to utilise InputBox within their applications.