Click here to Skip to main content
15,891,136 members
Articles / Desktop Programming / WPF

Optimizing your Mobile .NET 3.0 WPF Application for a UMPC or Touch-enabled PC

Rate me:
Please Sign up or sign in to vote.
4.33/5 (5 votes)
20 Mar 2007CPOL5 min read 43.7K   409   22   1
A simple application that is optimized for varying screen sizes and includes power/network status.

Screenshot - UMPCOptimizedSample.jpg

Introduction

The Ultra-Mobile PC is still a relatively new form factor in the PC World. I've written a sample application that illustrates some of the published design guidelines for UMPC's and includes a managed Power and Network aware class so you can add this functionality to your application.

Background

Ultra-Mobile PC's are a great new addition to the set of hardware platforms to run your applications. They run XP, and now Vista, and being very small and light they are well suited for mobile use. From a development point of view there is not that much to do (if anything) in order to make sure your application runs well on this PC's. The sample I've created focuses on three things:

  • Creating a re-usable header bar XAML component so my application can show the user mobile power/network status when in full-screen mode
  • Using the rich vector graphics of Windows Presentation Foundation (WPF) to scale my application's content well for any sized display resolution
  • Making sure I choose controls that work well with any input hardware (Mouse, Digitizer, Touch)

The sample includes the InkCube WPF sample that ships in the Windows Vista SDK as the main window content. I added this to have something of interest in this application, but this could be any XAML code.

The sample I chose allows you to create ink on any side of a cube and in real-time. The ink is rendered on the cube while it is rotating (see screen shot). In adding the sample, however, I did modify the layout and controls slightly to be optimized for the smaller resolution touch displays.

Header Bar Sample Component Overview

In looking at the Origami Experience product that Microsoft ships on UMPC's, I created a 'headerbar' in XAML with some C# back-end code to provide my user with information about the system. The information is comprised of items that add value to a mobile user: Battery status, network connection status and system time/date.

There are many articles that include sample code for this functionality (such as this one by Dr.Neil Roodyn: Mobile PC Power Management) but I have included the managed wrappers for both network and power notification for use in this WPF application. I also added a few simple icons and tooltip data for the user and combined the two sets of notifications (Power and Network Status) into one class in the application.

The following sections detail the code I used and reasons for some of the layout choices:

Full Screen Mode

It's pretty obvious how to implement this Full Screen mode, which makes it an inexpensive addition to any application, and allows it to utilize the entire real estate of the display. Here is the code:
C#
/// <summary />
/// Toggle between windowed and full-screen mode
/// to make use of the full abmount of screen real estate
/// </summary />
void OnFullScreenClick(object sender, RoutedEventArgs e)
{
    if (Application.Current.MainWindow.WindowStyle != WindowStyle.None)
    {
        // Show the minimize/close buttons only when in full screen
        this.MinimizeControl.Visibility = Visibility.Visible;
        this.CloseControl.Visibility = Visibility.Visible;
        //Set the window style and state to be borderless and maximized
        Application.Current.MainWindow.WindowState = WindowState.Maximized;
        Application.Current.MainWindow.WindowStyle = WindowStyle.None;
        // Set the text to the restore symbol (using Martlett font)
        this.FullScreentext.Text = "2";
    }
    else
    {
        // Hide the minimize/close buttons when windowed
        this.MinimizeControl.Visibility = Visibility.Collapsed;
        this.CloseControl.Visibility = Visibility.Collapsed;
        //Set the window style and state to be 'normal' windowed
        Application.Current.MainWindow.WindowStyle = 
            WindowStyle.SingleBorderWindow;
        Application.Current.MainWindow.WindowState = WindowState.Normal;
        // Set the text to the maximize symbol (using Martlett font)
        FullScreentext.Text = "1";
    }
}

Even though this is a WPF sample, I still work with a lot of developers using Native C++ Win32 APIs. Just in case you want this type of behavior in your Win32 application, here is the C++ version:

C++
// Toggle the window mode to/from fullscreen
BOOL ToggleFullScreen(HWND hWnd)
{
    WINDOWINFO wi;
    WINDOWPLACEMENT wp;
    long lWindowStyle = GetWindowLong(hWnd, GWL_STYLE);
    GetWindowInfo(hWnd, &wi);
    GetWindowPlacement(hWnd, &wp);

    // Is the window in fullscreen mode right now?
    if(wp.showCmd == SW_SHOWMAXIMIZED)
    {
        // We are full screen, switch to windowed
        SetWindowLong(hWnd, GWL_STYLE, lWindowStyle | WS_BORDER );
        wp.showCmd = SW_SHOWNORMAL;
        wp.length = sizeof(wp);
        SetWindowPlacement(hWnd, &wp);
    }
    else
    {
        // We are windowed, switch to full screen
        SetWindowLong(hWnd, GWL_STYLE, lWindowStyle & ~WS_BORDER );
        wp.showCmd = SW_SHOWMAXIMIZED;
        wp.length = sizeof(wp);
        SetWindowPlacement(hWnd, &wp);
    }
    return true;
}

Power and Network Status

Smart use of power is a must in today's mobile world. I have re-purposed some existing sample code to present icons for power status and network status in this sample. To use the code, you need to instantiate the PowerNetworkAware class and add handlers to watch for system changes to either power or network status. The calls for both of these topics are still from Win32, but the managed wrappers are included to make it easier to call from .NET. Here is a snippet of that code:
C#
void OnLoaded(object sender, RoutedEventArgs e)
{
    // Create the power and network aware class
    powerAndNetworkStatus = new PowerNetworkAware();

    // Register a delegate for the power related event
    powerModeChangeHandler = new 
        PowerModeChangedEventHandler(OnPowerModeChange);
    SystemEvents.PowerModeChanged += powerModeChangeHandler;

    // Register a delegate for the network related event
    networkChangedHandler = new NetworkAvailabilityChangedEventHandler(
        NetworkChange_NetworkAvailabilityChanged);
    NetworkChange.NetworkAvailabilityChanged += networkChangedHandler;

    // Wire up power awareness
    UpdatePowerStatus();
    // Wire up network status
    UpdateNetworkStatus();
}

The event handlers simply call the UpdatePowerStatus or UpdateNetworkStatus helpers to update the PowerNetworkAware class data and then choose which icons to display.

C#
/// <summary />
/// Invoked when the network status changes.
/// Changes icon and tooltip accordingly.
/// </summary />
void UpdateNetworkStatus()
{
    this.powerAndNetworkStatus.EnumerateNetworks();

    ToolTip myTooltip = new ToolTip();
    myTooltip.Content = powerAndNetworkStatus.currentNetworkLabel;
    this.NetworkStatusIndicator.ToolTip = myTooltip;

    String networkImageName = @"Images/wirelessgood.ico";

    if (powerAndNetworkStatus.networkStatus == "Disconnected")
    {
        networkImageName = @"Images/wirelessnone.ico";
    }
    else if (powerAndNetworkStatus.networkStatus == "Connectivity Lo")
    {
        networkImageName = @"Images/wirelesslow.ico";
    }

    // Create source.
    BitmapImage bi = new BitmapImage();
    // BitmapImage.UriSource must be in a BeginInit/EndInit block.
    bi.BeginInit();
    bi.UriSource = new Uri(networkImageName, UriKind.RelativeOrAbsolute);
    bi.EndInit();

    this.NetworkStatusIndicator.Source = bi;
}

The icons for power and network will update themselves based on the system events above. Since your machine may be connected to more than one network, I've chosen to display the status, name and speed of the fastest available network. So if you're running on a notebook/tablet with both wireless and wired Ethernet, you'll get the status of the wired connection until you un-plug it.

I've added a click handler for these items as well so the user can get to the associated control panel applets. Following is the code I used for this:

C#
void PowerStatusClick(object sender, RoutedEventArgs e)
{
    Process.Start("rundll32", "shell32,Control_RunDLL powercfg.cpl");
}
void NetworkStatusClick(object sender, RoutedEventArgs e)
{
    Process.Start("rundll32", "shell32,Control_RunDLL ncpa.cpl");
}

Tips on optimizing content for small resolutions (such as the UMPC)

Microsoft has published a Mobile PC Development Guide that suggests best-practices for developing Mobile PC and UMPC applications. This sample attempts to use those principles in its design. The main items to consider here are to:

  • Make sure the application scales well to the active resolution
  • Use controls that work well with both Mouse and Touch interaction - such as using buttons rather than slider controls
  • Create controls that are sized appropriately for the display - adding the full-screen ability and making buttons easily targeted with touch
  • Think about how the user may be interacting with this application if they are mobile - providing data at a glance and reducing the density of data

Other considerations for power management are to disable CPU intensive functionality if the PC is on battery or if the application is minimized. In this sample, I could have chosen to disable the rotating, animated cube if the application is minimized or not in the foreground. This would reduce the load on the CPU and in turn, save battery power.

Points of Interest

Aside from the design guidelines and existing Power/Nework samples I used in researching this, I found the Viewbox in WPF to be the perfect control in making the content of my application scale well for any resolution/display. Each of the controls I used for the header bar are a gray-based gradient so they remain colourless. This is interesting since I chose to load whatever desktop image that Windows is currently using as the background of this sample. Having colourless controls enables them to work well with any background color/image.

History

9th of March, 2007 - Created article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Other
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralBug when updating Network Status Pin
Daniel Kornev11-Feb-09 13:13
Daniel Kornev11-Feb-09 13:13 
Hi there,

If you'll try to run your sample in Windows 7 with .NET FX 3.5 SP1 and look on how your network status is changing you'll find that app is crashing.

This is because when Network Status Changed event is fired app calls directly UpdateNetworkStatus() and it doesn't call that in UI thread.

To fix this the following needs to be changed:

#region Power and Network Handlers
/// <summary>
/// Event handler to respond to NetworkAvailabilityChanged events.
/// This indicates that the network connection has just changed
/// between online and offline.
/// </summary>
public void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e)
{
    UpdateNetworkStatus(); // <-- change this to call of Dispatcher
}


Here are changes:

private delegate void UpdateNetworkStatusDelegate(); // <- this delegate is needed for calling of "UpdateNetworkStatus" from dispatcher

        #region Power and Network Handlers
        /// <summary>
        /// Event handler to respond to NetworkAvailabilityChanged events.
        /// This indicates that the network connection has just changed
        /// between online and offline.
        /// </summary>
        public void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e)
        {
// <- Updated call of NetworkStatusUpdate using Dispatcher
            this.NetworkStatusIndicator.Dispatcher.BeginInvoke(
            new UpdateNetworkStatusDelegate(UpdateNetworkStatus), DispatcherPriority.Normal, null);

        }


Warm Regards,
Daniel Kornev,
Program Manager, Microsoft.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.