Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
4/7/2010

Microsoft Corporation

February 2007

Summary

Learn how to build Microsoft Windows Mobile applications that successfully support the wide variety of device capabilities and available displays. This HOL will take 1 hour and 15 minutes to complete. (42 printed pages)

Download code sample from the Microsoft Download Center.

Applies To

Microsoft .NET Compact Framework version 1.0

Microsoft Visual C#

Microsoft Visual Studio 2005

Windows Mobile devices

The following applications are required to run this HOL:

  • Microsoft Windows XP Professional

  • Visual Studio 2005

    This HOL requires Visual Studio 2005 Standard, Professional, or Team System Editions. It will not work with any of the Express Editions. If you do not have the correct edition of Visual Studio 2005, find out how you can acquire it from the Visual Studio 2005 Developer Center .

  • Microsoft ActiveSync 4.0

    ActiveSync 4.0 allows for connectivity between a Windows Mobile–based device and your computer.

    Download and install ActiveSync 4.0 .

  • Windows Mobile 5.0 SDKs

    The Windows Mobile 5.0 SDKs for Pocket PC and Smartphone enable development for Windows Mobile–based devices in Visual Studio 2005:

    Download and install Windows Mobile 5.0 SDK for Pocket PC .

    Download and install Windows Mobile 5.0 SDK for Smartphone .

  • Set up your computer

    Follow the directions in the Additional Information section to set up your computer for this HOL.

Introduction

In this self-paced hands-on lab (HOL), you will learn to build Windows Mobile–based applications that successfully support the wide variety of device capabilities and available displays.

Lab 1: Writing Device-Independent Windows Mobile Applications with the .NET Compact Framework

The objective of this lab is to provide you with an understanding about how to build Windows Mobile–based applications that successfully support the wide variety of available displays.

In this HOL, you will perform the following exercises:

  • Identifying device characteristics

  • Adapting to device capabilities

  • Supporting both landscape and portrait displays

  • Adding high-resolution support

  • Supporting square and other displays

Exercise 1: Identifying Device Characteristics

In this exercise, you will learn how to determine the specific Windows Mobile version, whether the device is a Pocket PC or a Smartphone, and whether the device supports phone capabilities.

To open the WhoAmI.sln file in Visual Studio
  1. Open Microsoft Visual Studio 2005 by clicking Start| All Programs| Microsoft Visual Studio 2005| Microsoft Visual Studio 2005.

  2. In Visual Studio 2005, click File| Open| Project/Solution.

  3. In the Open Projectdialog box, browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_311\Exercises\WhoAmI.

  4. Select WhoAmI.sln, and then click Open.

  5. In Solution Explorer, double-click Form1.csto open Form1 in the form designer. The form should look like Figure 1. You will use the form to display platform and capabilities information for the current device.

    Note:
    After you open WhoAmI.sln, the solution, project, and source files should be visible in Solution Explorer in Visual Studio 2005. If Solution Explorer doesn't automatically appear, click View | Solution Explorer to make it visible.

    Figure 1. The WhoAmI project Form1.cs form in the form designer

    The form contains four Label controls. The label1and label2Label controls contain the text OS Versionand Device Typerespectively. The labelOsVersionLabel control is used at runtime to display the device's operating system version number. The labelDeviceTypeLabel control is used to display the specific device type.

To determine the device type
  1. In Solution Explorer, double-click PlatformInfo.csto open the file. The PlatformInfoclass is used to encapsulate the details of retrieving the platform information.

  2. Notice that the PlatformInfoclass contains a SystemParametersInfomethod and a SPI_GETPLATFORMTYPEconstant.

    The SystemParametersInfomethod is actually a Microsoft Win32® function that has been mapped into this class by using the DLLImportattribute. The SystemParametersInfofunction provides access to a wide variety of device-related information including a string that identifies the current device type. The SPI_GETPLATFORMTYPEconstant is the value that indicates to the SystemParametersInfofunction to return the device type string.

    To make retrieving the platform type string easier, provide a private property that encapsulates the details.

  3. Declare a private, static, read-only string property named SystemTypeString, as shown in the following code example.

    Copy Code
    static string SystemTypeString
    {
    	get
    	{
    }
    }
    
  4. In the getmethod, declare a StringBuilderinstance named platformTypeStringthat has an initial capacity of 255 characters, as shown in the following code example.

    Copy Code
    StringBuilder platformTypeString = new StringBuilder(255); 
    

    Now you're ready to call the SystemParametersInfofunction.

  5. When calling the SystemParametersInfofunction, pass the SPI_GETPLATFORMTYPEconstant as the first parameter, indicating that the platform type string is to be retuned. Pass the StringBuilderinstance's capacity as the second parameter, indicating the size of the buffer to receive the platform type string. The function expects this parameter to be an unsigned integer ( uint) whereas the StringBuilder.Capacityproperty is a signed integer ( int), so the property must be cast to an unsigned integer. Pass the StringBuilder instance as the next parameter; this is the buffer that the platform type string is copied into. Finally, pass a zero as the last parameter, as shown in the following code example.

    Copy Code
    SystemParametersInfo(SPI_GETPLATFORMTYPE,
    (uint)platformTypeString.Capacity, platformTypeString, 0);
    
  6. Return the contents of the platformTypeString StringBuilderinstance as a string by calling its ToStringmethod.

  7. Verify that the SystemTypeStringproperty looks like the following code example.

    Copy Code
    static string SystemTypeString
    {
    	get
    	{
    		StringBuilder platformTypeString = new StringBuilder(255);
    		SystemParametersInfo(SPI_GETPLATFORMTYPE,
    		 (uint)platformTypeString.Capacity, platformTypeString,
    0);
    		return platformTypeString.ToString();
    }
    }
    
    Note:
    The focus of this exercise is how to identify and respond to differences among devices. As a result, the simplest implementation of the SystemTypeStringproperty is used. If desired, the efficiency of the SystemTypeStringproperty can be improved by caching the type string. Caching the type string eliminates the need to repeatedly call the SystemParametersInfofunction. The easiest way to cache the type string is to declare a string member variable and store the returned string value in that member variable. The implementation would then be only to call the SystemParametersInfofunction once. This first call stores the returned string in the member variable. In all successive calls, the member variable value is returned directly.

    With the SystemTypeStringproperty complete, determining the device type is now quite simple. The Windows Mobile platform has only two device types: Pocket PC and Smartphone. With only these two choices, providing boolproperties, such as IsSmartPhoneand IsPocketPc, make it easy for an application to determine the specific device type without the application needing to deal with the details of examining the SystemTypeString.

  8. Declare a public, static read-only property named IsSmartPhonewith a return type of bool to create the IsSmartPhoneproperty, as shown in the following code example.

    Copy Code
    public static bool IsSmartPhone
    {
    	get {  }
    }
    
  9. Within the get method, use the SystemTypeStringproperty to retrieve the device type string. If the SystemTypeStringproperty contains the string "SmartPhone," the device is a Smartphone; therefore, the property should return true.

  10. Use the IndexOfmethod to determine if the SystemTypeStringproperty contains the string "SmartPhone." The IndexOfmethod returns the starting index of the string if it is found. A valid starting index will always be greater than or equal to 0. The IndexOfmethod returns -1 if the string is not found.

  11. Verify that the IsSmartPhoneproperty looks like the following code example.

    Copy Code
    public static bool IsSmartPhone
    {
    	get { return SystemTypeString.IndexOf("SmartPhone") >= 0; }
    }
    
  12. Create the IsPocketPcproperty in this same way that you did for the IsSmartPhoneproperty, except this time test the SystemTypeStringproperty for the string "PocketPC" (no spaces in PocketPC).

  13. Verify that the method looks like the following code example.

    Copy Code
    public static bool IsPocketPc
    {
    	get { return SystemTypeString.IndexOf("PocketPC") >= 0; ; }
    }
    

There are many cases where it may be useful to know if the current device has a phone. Obviously in the case of the Smartphone, a phone is always available but when it comes to Pocket PCs, some have phones and some don't. There also may be situations where a single application supports both Smartphones and Pocket PCs and may not be interested in the device type, but it may only be interested in whether or not a phone is available.

To determine phone support
  1. Like the IsSmartPhoneand IsPocketPcproperties, add an IsAPhoneproperty to the PlatformInfoclass. Just like the other properties, IsAPhoneis a public, static, read-only property with a return type of bool, as shown in the following code example.

    Copy Code
    public static bool IsAPhone
    {
    	get {  }
    }
    

    Unlike the device type, there's no function available across the Windows Mobile family of devices that identifies whether a device has a phone. Even though no function exists, there is a trait common to all Windows Mobile powered devices with a phone. That common trait is the presence of a system file, phone.dll in the \Windows folder.

    Knowing that all Windows Mobile powered devices with a phone have the file \Windows\phone.dll, the implementation of the IsAPhoneproperty simply uses the File.Existsmethod to determine if the file exists. If it does, the IsAPhoneproperty returns true.

  2. Verify that the IsAPhoneproperty looks like the following code example.

    Copy Code
    public static bool IsAPhone
    {
    	get { return File.Exists(@"\Windows\Phone.dll"); }
    }
    
    Note:
    Windows Mobile 5.0 introduced the State and Notifications Broker API. The State and Notifications Broker API provides the Microsoft.WindowsMobile.Status.SystemStateclass. The SystemStateclass provides access to a great deal of information regarding the features and capabilities of a device. All of these capabilities are accessible as properties on the SystemStateclass. Apropos to this exercise is the SystemState,PhoneRadioPresentproperty. The PhoneRadioPresentproperty returns trueif the device has a phone, much like the IsAPhone property you created in this exercise. The reason the SystemState,PhoneRadioPresent property is not used in this exercise is that it's not available on Windows Mobile powered devices prior to Windows Mobile 5.0; therefore, it does not work if the application is run on a Pocket PC 2002, Pocket PC 2003, Pocket PC 2003 Second Edition, Smartphone 2003, or Smartphone 2003 Second Edition.

    With the PlatformInfoclass complete, you can now use it to display information about the current device using the Form1form in this project. You can also modify the application to display operating system version information.

To display the device information
  1. In Solution Explorer, right-click Form1.cs, and then click View Codeto open the Form1.cs file in Code view.

  2. Locate the Form1_Loadmethod.

  3. In the Form1_Loadmethod, add an if/else if/elsestatement block that tests the PlatformInfo.IsSmartPhonein the first ifstatement and tests PlatformInfo.IsPocketPcin the else ifstatement, as shown in the following code example.

    Copy Code
    if (PlatformInfo.IsSmartPhone)
    {
    }
    else if (PlatformInfo.IsPocketPc)
    {
    }
    else
    {
    }
    
  4. Add the code that is necessary to assign the device type information to the Textproperty of the labelDeviceTypecontrol. When the IsSmartPhoneproperty is true, assign "SmartPhone" to the labelDeviceType.Textproperty. When the IsPocketPcproperty is true, assign "Pocket PC" to the labelDeviceType.Textproperty. In all other cases assign "Unknown Device" to the labelDeviceType.Textproperty. (The situation where "Unknown Device" is assigned to the labelDeviceType.Textproperty should never happen.)

  5. Add the code to determine if the Pocket PC has a phone by adding an ifstatement immediately after the line that assigns "Pocket PC" to the labelDeviceType.Textproperty. The ifstatement tests the PlatformType.IsAPhoneproperty. When the property returns true, concatenate the string "Phone Edition" onto the end of the labelDeviceType.Textproperty.

  6. Verify that the complete Form_Loadmethod looks like the following code example.

    Copy Code
    private void Form1_Load(object sender, EventArgs e)
    {
    	if (PlatformInfo.IsSmartPhone)
    	{
    		labelDeviceType.Text = "SmartPhone";
    }
    	else if (PlatformInfo.IsPocketPc)
    	{
    		labelDeviceType.Text = "Pocket PC";
    		if (PlatformInfo.IsAPhone)
    			labelDeviceType.Text += " Phone Edition";
    }
    	else
    	{
    		labelDeviceType.Text = "Unknown Device";
    } 
    }
    

    The last thing to do is to assign the operating system version number to the labelOsVersion.Textproperty by using the Environmentclass. The Environmentclass provides basic information about the runtime environment. It has a static property named OSVersionthat provides information about the operating system version number and the current Windows platform, such as Win32NT or WinCE. To get the operating system version number use the OSVersion.Versionproperty. The Versionproperty provides information about the operating system version number including the major, minor, build, and revision components. The ToStringmethod returns the complete version number as a string.

    Assigning the version number to the labelOsVersion.Textproperty is the very last line in the function.

  7. Add the assignment statement outside the entire if/else if/elsestatement block. It should appear just before the function closing bracket ( }), as shown in the following code example.

    Copy Code
    labelOsVersion.Text = Environment.OSVersion.Version.ToString();
    

You've completed the application; now test the program to verify that it returns the information correctly.

To test the application
  1. In Visual Studio, locate the Target Device list, and then select Windows Mobile 5.0 Pocket PC Emulator, as shown in Figure 2.

    Figure 2. Selecting the target device in Visual Studio

  2. Click Debug| Start Debuggingto build and run the application.

  3. If the Deploy WhoAmIdialog box appears, verify that Windows Mobile 5.0 Pocket PC Emulatoris selected in the Devicelist, and then click Deploy.

    Note:
    The first time you deploy the application to the device emulator, it may take a few minutes while the emulator starts and the .NET Compact Framework runtime is installed.
  4. After the application starts, it should look like Figure 3. Notice that it correctly displays the OS Versionas 5.1.117and the Device Typeas Pocket PC.

    Figure 3. The WhoAmI application running on the Windows Mobile 5.0 Pocket PC Emulator

  5. Close the application by clicking the left soft key under the text, Exit.

  6. In Visual Studio in the Target Device list, select Windows Mobile 5.0 Pocket PC Phone Emulator.

  7. Click Debug| Start Debuggingto start the application.

    The application still displays the OS Versionas 5.1.1700, but the Device Type displays Pocket PC Phone Edition, which is correct for this emulator.

  8. Close the application by clicking the left soft key under the text, Exit.

    As a final test, run the application using the Smartphone emulator. The easiest way to do this test is to change the project from a Windows Mobile 5.0 Pocket PC project to a Windows Mobile 5.0 Smartphone project.

To change the project target
  1. In Visual Studio, click Project| Change Target Platform.

  2. On the Change Target Platformdialog box, expand the drop-down list under Change To.

  3. Select Windows Mobile 5.0 SmartPhone SDK, and then click OK.

  4. When prompted by the Microsoft Visual Studiodialog box that asks, Do you want to continue?, click Yes.

    The project will briefly close then reopen.

  5. In Solution Explorer, double-click Form1.cs. Notice the form designer now displays the application as a Smartphone application.

  6. Verify that Windows Mobile 5.0 SmartPhone Emulatoris selected in the Target Device list.

  7. Click Debug| Start Debuggingto start the application.

  8. Notice that the application looks like Figure 4. It displays an OS Versionof 5.1.117and a Device Typeof SmartPhone.

    Figure 4. The WhoAmI application running on a Windows Mobile 5.0 SmartPhone emulator

  9. Close the application by clicking the left soft key under the text, Exit.

  10. Close the solution by selecting File| Close Solution. If prompted to save any items, click Yes.

Exercise 2: Adapting to Device Capabilities

In this exercise, you will apply the techniques that you used in the previous exercise to modify a program so it adapts to the capabilities of each device. The goal is to provide a high-quality user experience across a wide range of Windows Mobile powered devices and to take advantage of the capabilities provided by new or high-end devices. When complete, the capabilities of the application will increase as the capabilities of the device increases.

To become familiar with the existing application and its limitations
  1. In Visual Studio 2005, click File| Open| Project/Solution.

  2. In the Open Projectdialog box, browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_311\Exercises\RealEstateMgr.

  3. Select RealEstateMgr.sln, and then click Open.

  4. Click Debug| Start Debuggingto start the application. The application appears, as shown in Figure 5.

    Figure 5. The RealEstateMgr application running in the Pocket PC 2003 emulator

    The application is a simple real estate application with a list of properties displayed in the data grid at the top of the form and a picture of the property displayed at the bottom of the form. This initial form is referred to as the Home View.

  5. To view the details of the currently selected property, tap the Detailsmenu. The details appear, as shown in Figure 6.

    Figure 6. The RealEstateMgr detail form

  6. Click Doneto close the Detailsform.

  7. Notice on the main form of the RealEstateMgr application that the current property photo is a large, red brick building.

  8. On the emulator, click Menu| Select New Photo. The standard OpenFileDialogis displayed, as shown in Figure 7, showing the contents of the \My Documents\Business folder, which contains the list of property photo image files for the application.

    Figure 7. The OpenFileDialog showing the list of property photo image files

  9. Click Image005in the OpenFileDialog. Notice that the main application form now displays a small white house.

    This is a case where the application provides the required functionality of allowing the user to select a new photo for the property, but the application falls short of providing a quality user experience. The user experience lacks in quality because users have no way of being sure that they're selecting the correct photo image file until after they make the selection. Only when the property photo image is displayed on the main form do users get any confirmation of having selected the right or wrong property photo image. If the device supports the ability to display image files such that users can browse thumbnails of the images rather than just the file names, the application should take advantage of that feature.

  10. On the emulator, click Menu| Call Home Owner. The application now looks like Figure 8.

    Figure 8. The RealEstateMgr displaying the home owner phone number

    The Pocket PC 2003 emulator does not provide phone support; therefore, the application displays the phone number and lets the user type it into their separate mobile phone manually. Of course, many Windows Mobile powered devices provide phone support, so the application should take advantage of that support if it is available and automatically place the call.

  11. Click OKto close the Owner Phone Numbermessage.

  12. Click Menu| Exitto close the application.

    Windows Mobile 5.0 introduced a new feature that allows users to browse a list of image files by viewing thumbnails of the images rather than viewing the list of file names. You will now modify the application to take advantage of this capability, so the application will still function properly on pre-Windows Mobile 5.0 devices. The updated application provides the browse-by-thumbnail feature on devices running Windows Mobile 5.0 or later. For all other devices, the application continues to use the standard OpenFileDialogthat lists the files by name.

The project currently targets the Pocket PC 2003 SDK. To take advantage of the Windows Mobile 5.0 features, the project must target the Windows Mobile 5.0 Pocket PC SDK. Targeting Windows Mobile 5.0 does not prevent the application from running on pre-Windows Mobile 5.0 devices such as Pocket PC 2003.

To add photo image browsing
  1. In Visual Studio, click Project| Change Target Platformto change the project target.

  2. In the Change Target Platformdialog box, expand the drop-down list under Change To, click Windows Mobile 5.0 Pocket PC SDK, and then click OK.

  3. When prompted by the Microsoft Visual Studiodialog box that asks, Do you want to continue?, click Yes.

    The project will briefly close, and then will reopen.

  4. In Solution Explorer, double-click Form1.csto open it in the form designer.

  5. Click Menuto expand the Form1 menu. The menu appears, as shown in Figure 9.

    Figure 9. The Form1 menu

  6. Double-click the Select New Photocommand. This command opens Form1.cs in Code view and places the cursor in the Select New Photoclick event handler, menuSelectNewPhoto_Click.

  7. Review the current implementation of the menuSelectNewPhoto_Clickmethod. Using the standard OpenFileDialogclass, the menuSelectNewPhoto_Clickmethod sets the directory and file filter (*.jpg) information and then displays the OpenFileDialog. It stores the DialogResult( OKor Cancel) in the dlgResultvariable and the user's selected file in the selectedFilevariable. The menuSelectNewPhoto_Clickmethod finishes by checking the dlgResultvariable to verify that the user did select a file; if so, the new property photo image file is associated with the property record.

    As was noted at the beginning of this exercise, the browse-by-thumbnail feature is available only to devices running Windows Mobile 5.0 and later; therefore, the application must verify that the device is running Windows Mobile 5.0 or later before using the browse-by-thumbnail feature. To check the operating system version number in this case, you don't need the entire version number, but you need only the major version number because that's what indicates whether the device is running Windows Mobile 5.0 versus an earlier version.

  8. Immediately following the selectedFilevariable declaration, add an if/elsestatement block that checks the Majorproperty of the Environment.OSVersion.Versioninstance. The ifstatement condition checks whether the Majorproperty is less than 5. The true part of the ifblock should include the existing six lines from the SelectPictureByNameDialogvariable declaration through the assignment of the SelectPictureByNameDialog.FileNameproperty to the selectedFilevariable, as shown in the following code example.

    Copy Code
    if (Environment.OSVersion.Version.Major < 5)
    {
    	OpenFileDialog SelectPictureByNameDialog = new
    OpenFileDialog();
    	SelectPictureByNameDialog.InitialDirectory =
    _imageFolderShortName;
    	SelectPictureByNameDialog.Filter = _imageFilter;
    	SelectPictureByNameDialog.FilterIndex = 1;
    	dlgResult = SelectPictureByNameDialog.ShowDialog();
    	selectedFile = SelectPictureByNameDialog.FileName;
    }
    else
    {
    }
    

    For devices with Windows Mobile 5.0 or later, the application will use the new SelectPictureDialogclass. The SelectPictureDialogclass is not part of the .NET Compact Framework library, but rather it is part of the Windows Mobile 5.0 managed library.

    Using any of the classes in the Windows Mobile 5.0 managed library requires you to reference one of the Microsoft.WindowsMobileassemblies.

  9. In Visual Studio, click Project| Add Referenceto add the assembly reference.

  10. In the Add Referencedialog box, select Microsoft.WindowsMobile.Forms, and then click OK.

    Note:
    The Add Referencedialog box includes several assemblies whose name ends in Forms. Be sure to select the Microsoft.WindowsMobile.Formsassembly and not the Microsoft.WindowsCE.Formsor System.Windows.Formsassemblies.
  11. Locate the existing usingdeclarations at the top of the Form1.cs file, and then add a using reference for the "Microsoft.WindowsMobile.Forms" namespace.

    Now you're ready to add the code to use the SelectPictureDialogclass.

  12. In the elseblock of the if/elsestatement block in the menuSelectPhoto_Clickmethod, declare and create a new instance of the SelectPictureDialogclass named selectPictureDialog, as shown in the following code example.

    Copy Code
    else
    {
    	SelectPictureDialog selectPictureDialog = new
    SelectPictureDialog();
    }
    

    The program includes the constants _imageFolderand _imageFilterthat contain the folder and filter values that are required to select the property picture image file.

  13. Immediately following the selectPictureDialogvariable declaration and still within the else block, set the InitialDirectoryand Filter properties of the selectPictureDialogvariable to the _imageFolderand _imageFilterconstants respectively. There is one filter value (*.jpg), so set the FilterIndexproperty to 1, as shown in the following code example.

    Copy Code
    selectPictureDialog.InitialDirectory = _imageFolder;
    selectPictureDialog.Filter = _imageFilter ;
    selectPictureDialog.FilterIndex = 1;
    
    Note:
    Be sure to set the selectPictureDialog.InitialDirectoryproperty to the _imageFolderconstant and not the _imageFolderShortNameconstant, as you did for the selectPictureByNameDialog.InitialDirectoryproperty. The selectPictureByNameDialogvariable is an instance of the OpenFileDialogclass. The OpenFileDialogclass only supports opening folders within the My Documents folder; therefore, the InitialDirectoryproperty is set to the subfolder name within the My Documents folder (Business in this case) rather than the full path (\My Documents\Business). The selectPictureDialogvariable is an instance of the SelectPictureDialogclass. The SelectPictureDialogclass supports opening files anywhere in the file system; therefore, the InitialDirectoryproperty must be set to the full path.
  14. As the last two statements in the else block, display the selectPictureDialoginstance by calling its ShowDialogmethod and assigning the return value to the dlgResultvariable. Then, assign the selectPictureDialog.FileNameproperty to the selectedFilevariable.

  15. Verify that the complete menuSelectPhoto_Clickmethod looks like the following code example.

    Copy Code
    private void menuSelectNewPhoto_Click(object sender, EventArgs e)
    {
    	DialogResult dlgResult;
    	string selectedFile;
    
    	if (Environment.OSVersion.Version.Major < 5)
    	{
    		OpenFileDialog SelectPictureByNameDialog = new
    OpenFileDialog();
    		SelectPictureByNameDialog.InitialDirectory =
    _imageFolderShortName;
    		SelectPictureByNameDialog.Filter = _imageFilter;
    		SelectPictureByNameDialog.FilterIndex = 1;
    		dlgResult = SelectPictureByNameDialog.ShowDialog();
    		selectedFile = SelectPictureByNameDialog.FileName;
    }
    	else
    	{
    		SelectPictureDialog selectPictureDialog = new
    SelectPictureDialog();
    		selectPictureDialog.InitialDirectory = _imageFolder;
    		selectPictureDialog.Filter = _imageFilter;
    		selectPictureDialog.FilterIndex = 1;
    		dlgResult = selectPictureDialog.ShowDialog();
    		selectedFile = selectPictureDialog.FileName;
    }
    
    	if (dlgResult == DialogResult.OK)
    	{
    		HouseViewDataSet.PropertyRow row = GetCurrentPropertyRow();
    		row.ImageFileName = Path.GetFileName(selectedFile);
    }
    }
    

You're now ready to test the new code that you've added. With these changes, it's no surprise that the application will run on a device that runs Windows Mobile 5.0. You may be wondering what will happen when the application is run on devices that are running earlier software, such as a Pocket PC 2003 or Pocket PC 2003 Second Edition. The good news is that the application runs fine on these earlier devices. Using the Windows Mobile 5.0 features do not prevent the application from running on these earlier devices as long as the application never tries to use the Windows Mobile 5.0 library. Like all .NET assemblies, the Microsoft.WindowsMobile.Formsassembly is not loaded until one of the types contained in the assembly is used. In this case that would be the SelectPictureDialogclass. The version number check in the menuSelectNewPhoto_Clickmethod prevents the SelectPictureDialogclass from being used on pre-Windows Mobile 5.0 devices. As result, the application never attempts to load the Microsoft.WindowsMobile.Formsassembly on these earlier devices.

To test property photo image selection on a Windows Mobile 5.0-based Pocket PC
  1. In the Target Devicelist, verify that Windows Mobile 5.0 Pocket PC Emulatoris selected to test the application's behavior on Windows Mobile 5.0.

  2. Click Debug| Start Debugging.

  3. When the application starts, click Menu| Select New Photo. Notice that the application shows the thumbnails of the property pictures, as shown in Figure 10.

    Figure 10. The Windows Mobile 5.0 SelectPictureDialog dialog

  4. Select one of the thumbnails. The selected image is now associated with the property.

    The application now allows the user to select the appropriate picture unlike the earlier version of the application that required the user to know the file name of the desired image.

  5. Click Menu| Exitto close the application.

    In the Target Devicelist, you'll notice that there are no Pocket PC 2003 emulators displayed. The Pocket PC 2003 emulators are not displayed because Visual Studio 2005 only shows those emulators that are associated with the SDK the project is targeting. To test the application with an emulator that is not part of the targeted SDK, you must treat the emulator like an actual device.

Conclusion

Note:
The technique you will use to test the application with the Pocket PC 2003 emulator could have been used at the end of Exercise 1 to run the WhoAmI application on the Windows Mobile 5.0 Smartphone emulator as an alternative to changing the project to target the Windows Mobile 5.0 Smartphone SDK. In Exercise 1, both techniques are equally valid because the WhoAmI application has no features that are specific to the Windows Mobile 5.0 Smartphone SDK or the Windows Mobile 5.0 Pocket PC SDK. In this exercise, retargeting the project is not an option. The application is being verified to run on Pocket PC 2003 but must maintain all of the Windows Mobile 5.0-related features. Retargeting the project to Pocket PC 2003 would interfere with the need to include Windows Mobile 5.0 features.
To test property photo image selection on Pocket PC 2003 Second Edition
  1. In Visual Studio, click Tools| Device Emulator Managerto open the Device Emulator Manager.

  2. In the Device Emulator Manager, locate Pocket PC 2003 SE Emulator; you may need to expand the Pocket PC 2003node. Right-click Pocket PC 2003 SE Emulator, and then select Connect.

    The emulator starts and a green arrow appears to the left of Pocket PC 2003 SE Emulatorin the Device Emulator Manager.

  3. After the emulator starts, right-click Pocket PC 2003 SE Emulatorin the Device Emulator Manager, and then select Cradle.

    Cradling the emulator starts ActiveSync. ActiveSync may take a few moments to start, so be patient until you see the New Partnershipdialog box displayed.

    Note:
    The ActiveSync New Partnershipdialog box has the text Set Up a Partnershipdisplayed in large letters near the top of the emulator. This is the dialog box that you are looking for. Even though the dialog box is technically the New Partnershipdialog box, the Set Up a Partnershiptext is much more easily seen.
  4. When prompted by the New Partnershipdialog box, select Guest partnership, and then click the Nextbutton.

    Choosing the Guest partnershipestablishes an ActiveSync connection without attempting to synchronize content between the emulator and your desktop computer. After the emulator is cradled and the ActiveSync connection is established, the Pocket PC 2003 SE emulator appears on your desktop computer (or virtual PC) as a real device.

  5. In the Target Devicelist, select Windows Mobile 5.0 Pocket PC Device.

  6. Click Debug| Start Debugging. The application starts in the Pocket PC 2003 SE emulator.

  7. On the emulator, click Menu| Select New Photo. Notice the application lists the property photo image file names as it originally did, as shown in Figure 7.

  8. Select one of the files. The selected property photo image contained in the file is now associated with the property.

  9. Click Menu| Exitto close the application.

  10. Disconnect the Pocket PC 2003 SE emulator from ActiveSync by right-clicking Pocket PC 2003 SE Emulator in the Device Emulator Manager, and then selecting Uncradle.

Another opportunity to provide the user with a higher quality experience is to take advantage of phone capabilities. You will now modify the application so it automatically dials the phone if the device provides phone capability. If the device does not have a phone, the application displays the phone number in a message box just as it did originally.

To add automatic phone dialing
  1. In Solution Explorer, right-click Form1.cs, and then select View Code.

  2. Locate the Call Home Ownermenu and click event handler, menuCallHomeOwner_Click.

    Notice that the current implementation is very simple with only one line—a call to the MessageBox.Showmethod to display the phone number.

    Note:
    For simplicity, the application displays the same phone number for each property owner.
  3. In Solution Explorer, double-click PlatformInfo.csto open the file. Notice that the file contains an implementation of the PlatformInfoclass. This implementation is identical to the PlatformInfoclass that you created in Exercise 1 and contains the same three public properties: IsSmartPhone, IsPocketPc, and IsAPhone. Using this class, you will modify the Form1.menuCallHomeOwner_Clickmethod to adapt its behavior to the device capabilities.

    Prior to Windows Mobile 5.0, there was no .NET Compact Framework class that provided phone dialing ability. To make a call, a .NET Compact Framework application would instead use the platform invoke facility to call the Win32 PhoneMakeCallfunction.

  4. In Solution Explorer, double-click NativeFunctionHelper.csto open the file.

  5. Locate the MakeCallmethod.

    The MakeCallmethod is a .NET Compact Framework friendly method that encapsulates the details of using the Win32 PhoneMakeCallfunction. The MakeCallmethod takes two parameters: a stringparameter that contains the phone number to dial and a boolparameter that indicates whether to prompt the user before placing the call. You will use the MakeCallmethod to add automatic dialing to the Form1.menuCallHomeOwner_Clickmethod.

  6. Again, open Form1.cs in Code view, and then locate the menuCallHomeOwner_Clickmethod.

  7. Add an if/elsestatement block to the menuCallHomeOwner_Clickmethod, as shown in the following code example. The ifcondition tests the device phone capability using the PlatformInfo.IsAPhoneproperty. The existing MessageBox.Showmethod call is in the else block.

    Copy Code
    if (PlatformInfo.IsAPhone)
    {
    }
    else
    {
    	MessageBox.Show(PropertyPhoneNumber, @"Owner Phone Number");
    }
    
  8. In the truepart of the ifblock, call the NativeFunctionHelper.MakeCallmethod passing the Form1.PropertyPhoneNumberproperty as the first parameter and falseas the second parameter, as shown in the following code example. Passing false as the second parameter indicates that the call is to be placed without prompting the user.

    Copy Code
    NativeFunctionHelper.MakeCall(PropertyPhoneNumber, false);
    

    At this point, the application provides the required functionality of automatically placing the phone call if the device has a phone. There is one more step you can take to make the application even better.

    The Windows Mobile 5.0 managed library provides a Phoneclass. The Phoneclass has a Talkmethod that, when called, automatically places the call. Because the Phone.Talkmethod is currently implemented, it provides no additional features over the NativeFunctionHelper.MakeCallmethod; however, this fact may not remain true indefinitely. As the Windows Mobile platform evolves, factors like security may make avoiding calls directly to native Win32 functions beneficial.

    The Phoneclass is implemented in the Microsoft.WindowsMobile.Telephonyassembly.

  9. Add a reference to the Microsoft.WindowsMobile.Telephonyassembly following the same steps that you used to add a reference to the Microsoft.WindowsMobile.Formsassembly previously in this exercise.

  10. At the top of Form1.cs, add a usingdeclaration for the "Microsoft.WindowsMobile.Telephony" namespace.

    Whether using the Win32 function or the managed method, placing the call requires that the device has a phone; therefore, the logic to determine whether to use the native function or managed method will be in the trueside of the existing ifblock that checks the PlatformInfo.IsAPhoneproperty.

  11. In the trueside of the existing if block, add another if/elsestatement block, as shown in the following code example. The condition of the new ifstatement tests whether the Windows Mobile version is less then 5 using the Environment.OSVersion.Version.Majorproperty. The existing call to the NativeFunctionHelp.MakeCallmethod is in the true side of the new ifblock.

    Copy Code
    if (Environment.OSVersion.Version.Major < 5)
    {
    	NativeFunctionHelper.MakeCall(PropertyPhoneNumber, false);
    }
    else
    {
    }
    
  12. In the elseside of the statement block, declare and create an instance of the Phoneclass named p, and then call the p.Talkmethod passing the Form1.PropertyPhoneNumberproperty.

  13. Verify that the complete menuCallHomeOwner_Clickmethod looks like the following code example.

    Copy Code
    private void menuCallHomeOwner_Click(object sender, EventArgs e)
    {
    	if (PlatformInfo.IsAPhone)
    	{
    		if (Environment.OSVersion.Version.Major < 5)
    		{
    			NativeFunctionHelper.MakeCall(PropertyPhoneNumber,
    false);
    	}
    		else
    		{
    			Phone p = new Phone();
    			p.Talk(PropertyPhoneNumber);
    	}
    }
    	else
    	{
    		MessageBox.Show(PropertyPhoneNumber, @"Owner Phone
    Number");
    }
    }
    
To test the automatic dialing feature on Windows Mobile 5.0 Pocket PC Phone Emulator
  1. In the Target Devicelist, select Windows Mobile 5.0 Pocket PC Phone Emulator.

  2. Click Debug| Start Debugging.

  3. When the application starts, click Menu| Call Home Owner. Notice that the device displays the phone application and dials the call, as shown in Figure 11.

    Figure 11. The phone interface dialing a call that was initiated by the application

  4. End the phone call by clicking the Endbutton on the phone application, and then minimize the phone application by clicking the Xin the upper-right corner.

  5. Close the application by clicking Menu| Exit.

To test the automatic dialing feature on Windows Mobile 5.0 Pocket PC
  1. In the Target Devicelist, select Windows Mobile 5.0 Pocket PC Emulator.

  2. Click Debug| Start Debugging.

  3. When the application starts, click Menu| Call Home Owner. Notice that the application displays the phone number in a message box—just as it originally did, as shown in Figure 8. This is the correct behavior because the Windows Mobile 5.0 Pocket PC Emulator does not have a phone.

  4. Click OKto close the message box, and then close the application by clicking Menu| Exit.

Exercise 3: Supporting Both Landscape and Portrait Displays

An increasing number of Windows Mobile powered devices have landscape displays. Some devices may be landscape all of the time; others may switch dynamically between portrait and landscape. To maximize the opportunity for your Windows Mobile–based applications and to minimize undesirable support calls, your applications should support both portrait and landscape display. The application that you used in Exercise 2, RealEstateMgr currently supports portrait display. In this exercise, you will modify the RealEstateMgr application to support both portrait and landscape displays.

To view the existing application in landscape
  1. In Visual Studio 2005, click File| Open| Project/Solution.

  2. In the Open Projectdialog box, browse to C:\Program Files\Windows Mobile Developer Samples\HOLs\MEDC06_HOL311\Exercises\RealEstateMgr.

  3. Select RealEstateMgr.sln, and then click Open.

  4. In Solution Explorer, double-click Form1.csto open the file in the form designer.

  5. Review the Form1.cs application form, as shown in Figure 12. Notice that the controls all use absolute positioning and assume a screen size of 240 x 320.

    Figure 12. Main application form using absolute positioning displayed as portrait

  6. In Visual Studio, open PropertyDetailForm.csin the form designer.

  7. Review the PropertyDetailForm.cs application form, as shown in Figure 13. Notice that as with Form1.cs, the controls all use absolute positioning and assume a screen size of 240 x 320.

    Figure 13. Application detail form using absolute positioning displayed as portrait

  8. In the Target Device list, select Windows Mobile 5.0 Pocket PC Emulatorif it's not already selected.

  9. Click Debug| Start Debuggingto start the application.

  10. While viewing the application's Home Viewscreen, rotate the emulator to landscape by clicking the emulator's App Launch 2button, which is below the screen and to the right of the navigation pad. It has a symbol that looks like a calendar, as shown in Figure 14.

    Figure 14. The Windows Mobile 5.0 Emulator's App Launch 2 button that rotates the emulator display

    Figure 15 shows the application running on a landscape display. Notice in Figure 15 that the application immediately becomes difficult to use because the property photo is obscured. Notice also that the application isn't making good use of available space. There is room on the screen to display both the grid and the property photo; the controls just need to be rearranged a little.

    Figure 15. The main application form displaying incorrectly in landscape

  11. Rotate the emulator back to portrait by clicking the emulator's App Launch 2button.

  12. Click Details. The Detailsscreen appears, as shown in Figure 16.

    Figure 16. Application detail form displayed in portrait

  13. Rotate the emulator again to landscape, and then notice that the Detailsscreen is also obscured when the application is in landscape.

  14. Return the emulator to portrait, and then click Doneto close the Detailsscreen.

  15. Click Menu| Exitto close the application.

    Handling both landscape and portrait displays requires that the application support some form of dynamic layout. One possible solution is to design separate portrait and landscape versions of the application forms. This technique works, but keeping the two sets of forms synchronized can be challenging. A more common technique for handling both landscape and portrait displays is to have one set of forms with the forms dynamically moving the controls on the form between a portrait-friendly and a landscape-friendly layout.

To simplify managing the different display layouts, the project includes the DisplayInfoclass that is in the DisplayInfo.cs file.

To update the application to support landscape
  1. Open DisplayInfo.cs, and then locate the GetDisplayModemethod.

    The GetDisplayModemethod encapsulates the details of determining whether the current display is portrait or landscape. As you can see, the determination is rather simple. The method simply compares the screen's height and width. The GetDisplayModemethod's return value is an enumeration, DisplayMode, that contains two values: Portraitand Landscape.

  2. In Solution Explorer, double-click Form1.csto open the file in the form designer.

  3. Ensure that the form is the currently selected control by single-clicking anywhere within the form where no controls appear.

  4. In the Propertiespane, select the events view by clicking the Events(lightning bolt) button on the toolbar, as shown in Figure 17.

    Figure 17. List of events for the Form1 class

  5. Scroll down the list of events until the Resizeevent is visible, and then double-click Resize. This step adds the Resize event handler for Form1, Form1_Resize; displays Form1in Code view; and positions the cursor within the Form1_Resizemethod.

  6. In the Form1_Resizefunction, call the AdjustFormLayoutmethod, as shown in the following code example.

    Copy Code
    Private void Form1_Resize(object sender, EventArgs e)
    {
      AdjustFormLayout();
    }
    
  7. Locate and review the AdjustFormLayoutmethod.

    The AdjustFormLayoutmethod handles the details of moving between a portrait and landscape layout. Notice that the implementation is simply to call the DisplayInfo.GetDisplayModemethod and then modify the size and position of the controls as appropriate for the current display mode (portrait or landscape).

To test the application's support of both landscape and portrait displays
  1. In Visual Studio, click Debug| Start Debugging. Notice that the application still displays correctly when displayed in portrait.

  2. While viewing the application's Home Viewscreen, click the emulator's App Launch 2button to rotate the emulator to landscape. Figure 18 shows the application now displaying correctly in landscape.

    Figure 18. The application displaying correctly in landscape

  3. Return the emulator to portrait by clicking the App Launch 2button again.

  4. Close the application by clicking Menu| Exit.

    Note:
    You may notice that when you view the Property Detail form in landscape, some of the display is cut off. The Property Detail form can be updated to properly support landscape display by repositioning the controls, just as the AdjustFormLayoutmethod did in the main form. Alternatively, you can make the PropertyDetailFormform more orientation-aware by setting the PropertyDetailFormform AutoScroll property to true. With the AutoScroll property set to true, the PropertyDetailFormform automatically adds scroll bars to the form in the event that the form controls do not fit on the screen—as is the case when the PropertyDetailFormform is displayed in landscape.

Exercise 4: Adding High-Resolution Support

Another trend in Windows Mobile powered devices is high-resolution displays. Historically, Windows Mobile Pocket PCs have had a screen resolution of 96 dpi, and many devices still have this resolution. Other devices with high-resolution displays have 192 dpi. The purpose of a high-resolution display is not to put more information on the screen; rather it is to provide a higher quality display. These high-resolution displays provide a very sharp display and allow applications to render rich, high-quality graphics and smooth text. When your application is run on a device with a high-resolution display, the controls on your application forms must be scaled appropriately.

To view the existing application in high resolution
  1. In the Target Devicelist, select Windows Mobile 5.0 Pocket PC VGA Emulator.

  2. Click Debug| Start Debuggingto start the application.

  3. Notice in Figure 19 that all of the controls are crowded into the top-left corner of the form. To properly handle the different screen resolutions, each control on the form must have its size and position adjusted to match the display.

    Figure 19. The application displaying incorrectly on a high-resolution display

  4. Click Menu| Exitto close the application.

To update the application to support high-resolutions
  1. Open the DisplayManager.cs file, and then locate the GetDisplayRatiosmethod.

    Notice that the method has three parameters; the first is a reference to a control in the application. This parameter can be any control, but in this application, it will always be an instance of the Formclass. The second and third parameters are values returned by this method that contains scaling ratios for the application display. The widthRatioparameter indicates how much to scale the control's size and position on the X axis (left-to-right). The heightRatioparameter is the same except it represents the Y axis (up-and-down).

    Notice the two constants just above the GetDisplayRatiomethod: designDpiXand DesignDpiY. These both have the value 96, which represents the resolution of the form designer in Visual Studio. These constants serve as the basis for the scaling ratios.

    Note:
    The forms designer supports designing in both 96 dpi and 192 dpi. The Form Factorproperty allows you to select the device that you would like to design for. The Form Factoris a property available on the Formclass when working in Visual Studio; you can select a desired Form Factorsuch as Windows Mobile 5.0 Pocket PC or Windows Mobile Pocket PC VGA. The design-time form will use the characteristics of the selected Form Factor. The default Form Factorfor projects that target the Windows Mobile 5.0 Pocket PC SDK is Windows Mobile 5.0 Pocket PC, which has a resolution of 96 dpi.
  2. In the GetDisplayRatiosmethod, locate the call to the CreateGraphicsmethod on the ctrlparameter.

    This call returns an instance of the Graphicsclass. The Graphicsclass contains a wide variety of properties and methods that provide information about the current display and allow you to interact with the display. The two properties required for this method are DpiXand DpiY, which contain the dots per inch of the X and Y axes for the current device display.

    By knowing the dpi values that the form was designed for and knowing the dpi of the current display, determining the scaling ratios for the X and Y axes is a simple matter of division, as is done in the last two lines of the GetDisplayRatiosmethod. These values will be used to adjust the size and position of the application controls.

    The program will use the scaling ratios from the GetDisplayRatiosmethod anytime it needs to handle the layout of the form controls. The form control layout is normally handled at the beginning of the application when controls are first being created and then when the user rotates the device display between portrait and landscape. Rather then call the GetDisplayRatiosmethod each time the layout needs to be updated; the method can be called once when the program first starts. To avoid repeatedly calling the GetDisplayRatiosmethod, the width and height ratios returned from the GetDisplayRatiosmethod need to be stored in class member variables. The two class member variables, _widthRatioand _heightRatio, are already declared and are intended for this purpose.

  3. Open Form1.cs in Code view, and then locate the Form1_Loadmethod.

  4. As the first line in the method, call DisplayInfo.GetDisplayRatiospassing the Form1class's thisreference, followed by the _widthRatioand _heightRatiomember variables. Remember to pass _widthRatioand _heightRatioas reference parameters, as shown in the following code example.

    Copy Code
    private void Form1_Load(object sender, EventArgs e)
    	{ 
    		DisplayInfo.GetDisplayRatios(this, ref _widthRatio, ref
    _heightRatio);
    
  5. Locate the ScaleFormControlsmethod within the Form1 class.

    The purpose of the ScaleFormControlsmethod is to reposition and resize the form's controls correctly for the current display resolution. To do this, the method uses the _widthRatioand _heightRatioclass member variables that are populated by the call to the GetDisplayRatiosmethod that you added to Form1_Loadmethod. You'll notice that the declarations for both of these class member variables are just a couple lines above the ScaleFormControlsmethod.

    The ScaleFormControlsmethod starts by calling the DisplayInfo.GetDisplayModemethod to determine if the current display is portrait or landscape. It then scales the size of the DataGridand PictureBoxcontrols. You'll notice that the scaling of the PictureBoxlocation varies depending on the orientation. The location changes because the PictureBoxcontrol must be positioned relative to the DataGridcontrol. In Portrait orientation, the PictureBoxis under the DataGridand has to move down to avoid being covered by the DataGridcontrol. In landscape, the PictureBoxis right of the DataGridand must move to the right to avoid being covered by the DataGridcontrol. The last thing the ScaleFormControlsmethod does is call the ScaleGridMembersmethod that scales the columns within the DataGridusing a similar technique to that used in the ScaleFormControlsmethod to scale the control.

    The ScaleFormControlsmethod handles the details of scaling the controls appropriately for the display resolution, and the AdjustFormControlsmethod handles the details of repositioning and resizing the controls appropriately for the current display orientation. To handle both issues correctly, the scaling must be done after the controls' positions and sizes for the current orientation are determined but before the controls are actually repositioned and resized.

  6. Locate the AdjustFormLayoutmethod (it's just above the ScaleFormControlsmethod). Notice that most of the code in this method handles the repositioning and resizing of the controls. The last three lines, however, assign the new size and location information to the controls.

  7. Add a call just above these three lines to ScaleFormControls, as shown in the following code example.

    Copy Code
    	ScaleFormControls(ref gridSize, ref pictureBoxLocation, ref
    pictureBoxSize);
    	propertyDataGrid.Size = gridSize;
    	propertyPictureBox.Location = pictureBoxLocation;
    	propertyPictureBox.Size = pictureBoxSize;
    }
    
To test that the application supports both high-resolution and standard-resolution displays
  1. In the Target Devicelist, select Windows Mobile 5.0 Pocket PC VGA Emulator.

  2. Click Debug| Start Debuggingto start the application.

  3. While viewing the application's Home Viewscreen, rotate the emulator orientation to landscape, as shown in Figure 20. In most cases, you'll be able to rotate the emulator by clicking the emulator's App Launch 2button as you did in previous exercises.

    Figure 20. The application correctly displayed in landscape on a high-resolution display

    In some cases, the screen resolution of your desktop computer (or virtual PC) may not provide enough space to allow you to access the emulator App Launch 2button. If you find this to be the case, change the display resolution to 1280 x 1024. To change the display resolution, right-click the computer (or virtual PC) desktop and select Properties. On the Display Propertiesdialog box, click the Settingstab, slide the Screen resolutionslider bar to 1280 x 1024, and then click OK. Now click the App Launch 2button on the emulator to rotate the emulator to landscape.

    If the desktop computer (or virtual PC) that you are using does not support a resolution of 1280 x 1024 (or any other resolution that provides enough screen space to access the emulator App Launch 2button), you will need to rotate the emulator by modifying the emulator properties. You can access the emulator properties by clicking File| Configureon the Windows Mobile 5.0 Pocket PC VGA Emulator menu. In the Emulator Propertiesdialog box, click the Displaytab, select 90from the Orientationlist, and then click OK. You'll notice that the emulator rotates to landscape, but the application is still displayed as portrait. The emulator App Launch 2button is now accessible. Click the App Launch 2button, and the application now redraws as landscape. Both the emulator and application are properly displayed in landscape.

    Note:
    The application doesn't redraw in the appropriate orientation when you change the emulator orientation by using the Emulator Propertiesdialog box. When changing the orientation by using the Emulator Propertiesdialog box, the emulator does not notify Windows Mobile of the orientation change; therefore, Windows Mobile cannot notify the application of the change in orientation. This is true for all applications running in the emulator.
  4. Click the App Launch 2button again to return the emulator to portrait, as shown in Figure 21.

    Figure 21. The application correctly displayed in portrait on a high-resolution display

    Note:
    If you had to rotate the emulator by changing the emulator properties in Step 3 because the App Launch 2button was not accessible in your desktop computer's (or virtual PC) supported screen resolutions, reverse Steps 4 and 5—close the application before rotating the emulator to portrait. If you rotate the emulator to portrait before closing the application, your desktop computer's (or virtual PC's) screen resolution may prevent you from accessing the application menu to close the application.
  5. Close the application by clicking Menu| Exit.

  6. Repeat the preceding steps using the Windows Mobile 5.0 Pocket PC Emulator to verify that the application still displays correctly in both portrait and landscape on a 96 dpi display.

Exercise 5: Supporting Square and Other Displays

In addition to the portrait and landscape displays, Windows Mobile also supports devices with square displays. Adding support for these devices requires a little more flexibility in the application. In this exercise, you will modify the application to work with square displays and any other displays that the application may encounter. Adding this flexibility ensures that the application provides a reasonable viewing experience on all Windows Mobile powered device displays—even those that may not exist yet.

To test the application on a square display
  1. In Visual Studio, select Windows Mobile 5.0 Pocket PC Square Emulatorin the Target Devicelist.

  2. Click Debug| Start Debuggingto start the application.

  3. Notice that the property picture is cut off, as shown in Figure 22.

    Figure 22. The application on a square display with part of the property picture cut off

  4. Click Menu| Exitto close the application.

    All of the application's display modifications so far have maintained the application's fundamental display format of having two forms. The main application form displays the list of properties and a picture of the currently selected property. The other form displays the property details when the user requests to see these details by clicking the Detailscommand on the main form. The two-form format works well for portrait and landscape displays.

    The space available on a square display makes maintaining the layout of the main form difficult because there isn't room on a square display to proportionally fit both the property listing and photo. In the case of the square display, allowing the property grid to occupy the entire main form and moving the property photo to a separate form creates a much more aesthetic and functional display.

In this exercise, that's exactly what you're going to do—modify the application so, in the case of a square display, the application uses three forms rather than the two forms that are used for portrait and landscape displays. In this three-form layout, the property listing occupies the entire main form, and the main form now has an additional command, View Photo, that displays the form containing the property photo. The property photo is now on its own form and displays the photo corresponding to the property that is currently selected on the main form when the user selects the View Photocommand. The process of viewing the property detail information is unchanged; property detail information is still on its own form and displays the details for the property that is currently selected on the main form when the user selects the Detailscommand.

To update the application to support square-display devices
  1. Open DisplayInfo.cs in Code view.

  2. Locate the DisplayModeenumeration, and then add a Simplevalue, as shown in the following code example.

    The DisplayMode.Simpleenumeration identifies that neither the portrait or landscape layouts are appropriate. A DisplayModevalue of Simpleindicates that the application is using the new three form layout.

    Copy Code
    enum DisplayMode
    {
    	Portrait,
    	Landscape,
    	Simple
    }
    
  3. Locate the GetDisplayModemethod in the DisplayInfoclass.

    This method will be modified to return the DisplayMode.Simplevalue in addition to Portraitand Landscape. One way to implement GetDisplayModeis to return Portraitwhen the screenBounds.Heightproperty is greater than the screenBounds.Widthproperty, Landscapewhen the reverse is true, and Simple when they are equal. The shortcoming in this implementation is that it assumes that either the portrait or landscape layout will work for all display types other than those that are exactly square. This is not a totally safe assumption.

    Although none exist today, there may be a time when devices have a nearly square display—where the display height is just a little greater than the display width or vice versa. In these cases, a square-like layout is more appropriate than portrait or landscape. To address this situation, the GetDisplayModemethod identifies ranges that each layout is appropriate for. In the case of the portrait layout, the display must have a width-to-height display ratio less than 0.8. For the landscape layout, the width-to-height display ratio must be greater than 1.3. Any display with a width-to-height ratio between 0.8 and 1.3 inclusive uses the Simplelayout.

    Note:
    There is no absolute rule about the appropriate width-to-height ratio for each of the display layouts, but the width-to-height ratios used in this exercise serve as a good guideline. The display layouts used in this exercise are based on the width-to-height display ratios used by currently available Pocket PCs. Today, all portrait display Pocket PCs have a display size of 240 x 320 or 480 x 640, both of which are a width-to-height display ratio just under 0.8 (0.75). Similarly, all landscape display Pocket PCs that are available today have a display size of 320 x 240 or 640 x 480, both of which are a width-to-height display ratio are greater than 1.3 (1.3333…). Although the portrait and landscape width-to-height display ratios are based on common Pocket PC display sizes, the ratios work equally well when determining layout requirements for Smartphones.
  4. Rather than hardcode the display ratio boundaries, declare two constants with a data type of floatjust before the GetDisplayModemethod. Name the constants minSimpleDisplayRatioand maxSimpleDisplayRatio. Assign the constants values of 0.8F and 1.3F respectively, as shown in the following code example.

    Copy Code
    const float minSimpleDisplayRatio = 0.8F;
    const float maxSimpleDisplayRatio = 1.3F;
    
  5. Within the GetDisplayModemethod just after the declaration of the screenBoundsvariable, calculate the width-to-height display ratio. First declare a variable named widthToHeightRatiowith a data type of float. Calculate the width-to-height display ratio by dividing the screenBounds.Widthproperty by the screenBounds.Heightproperty, and then assign the result to the widthToHeightRatiovariable. In the calculation, cast the Widthand Heightproperties to floator the calculation will use integer division (whole numbers only, no fractional values), as shown in the following code example.

    Copy Code
    float widthToHeightRatio = (float)screenBounds.Width /
    (float)screenBounds.Height;
    
  6. Modify the condition of the existing if/elsestatement block so the modevariable is assigned the DisplayMode.Portraitvalue when the widthToHeightRatiovariable is less than the minSimpleDisplayRatioconstant. Change the existing else to an else if statement with a condition that assigns the DisplayMode.Landscapevalue to the mode variable when the widthToHeightRatiois greater than the maxSimpleDisplayRatioconstant. Add an else block that sets the mode variable to the DisplayMode.Simplevalue if the other two conditions test false.

  7. Verify that the complete GetDisplayModemethod looks like the following code example.

    Copy Code
    public static DisplayMode GetDisplayMode()
    {
    	Rectangle screenBounds = Screen.PrimaryScreen.Bounds;
    	DisplayMode mode = DisplayMode.Simple ;
    	float widthToHeightRatio = (float)screenBounds.Width /
    (float)screenBounds.Height;
    	if (widthToHeightRatio < minSimpleDisplayRatio)
    	{
    		mode = DisplayMode.Portrait;
    }
    	else if (widthToHeightRatio > maxSimpleDisplayRatio)
    	{
    		mode = DisplayMode.Landscape;
    }
    	else
    	{
    		mode = DisplayMode.Simple;
    }
    	return mode;
    
    }
    
  8. With the DisplayInfo.GetDisplayModemethod complete, open ImageForm.csin the form designer.

    Notice that the form contains a PictureBoxcontrol whose Dockproperty is set to Fill. Other than being set to fill the form, this PictureBoxcontrol has the same properties as the PictureBoxcontrol on the main form. The ImageFormform is used only when the DisplayInfo.GetDisplayModemethod returns a DisplayMode.Simplevalue.

  9. Open ImageForm.cs in Code view.

    Notice that the implementation of the ImageFormclass has only one public member: the SetBindingSourcemethod. The SetBindingSourcemethod is used to set the BindingSourcefor the ImageFormclass to the same BindingSourceas the Form1 and PropertyDetailFormforms. The private members of the ImageFormclass are primarily housekeeping methods that are used to display the property photo each time the BindingSource'scurrent record changes.

  10. Open Form1.cs in Code view, and then locate the PropertyDetailFormmember variable declaration near the beginning of the class.

  11. Immediately following the _propertyDetailFormclass member declaration, declare a class member variable menuViewPhotowith a data type of MenuItem. Following the menuViewPhotoclass member declaration, add a class member declaration for the ImageFormform named _imageForm, as shown in the following code example.

    Copy Code
    Bitmap _imageBitmap;
    PropertyDetailForm _propertyDetailForm;
    MenuItem menuViewPhoto;
    ImageForm _imageForm;
    
  12. Add a new method to the Form1class named menuViewPhoto_Click. The menuViewPhoto_Clickmethod handles the click event for a command that you will be adding soon, so it must conform to the delegate signature that is required for menu Click event handlers, and it must have a return type of void and two parameters: an objectparameter and an EventArgsparameter.

  13. In the menuViewPhoto_Clickmethod, call the ShowDialogmethod on the _imageFormmember variable, but only do so when the _imageFormmember variable does not have a value of null, as shown in the following code example.

    Copy Code
    private void menuViewPhoto_Click(object sender, EventArgs e)
    {
    	if (_imageForm != null)
    		_imageForm.ShowDialog();
    }
    
  14. Locate the Form1_Loadmethod. In the Form1_Loadmethod, add an ifstatement block immediately following the call to DisplayImage. In the ifcondition, call the DisplayInfo.GetDisplayModemethod and test to see if the return value is DisplayMode.Simple, as shown in the following code example.

    Copy Code
    if (DisplayInfo.GetDisplayMode() == DisplayMode.Simple)
    {
    }
    
  15. In the if block, create the _imageForminstance, and then call the _imageForm.SetBindingSourcemethod passing in the propertyBindingSourceproperty, as shown in the following code example. The propertyBindingSourceis the same BindingSourceused by Form1 and the PropertyDetailFormclass. By binding to the propertyBindingSource, the property photo on the ImageFormautomatically stays synchronized with the property selection on Form1.

    Copy Code
    _imageForm = new ImageForm();
    _imageForm.SetBindingSource(propertyBindingSource);
    

    In the DisplayMode.Simplelayout, the property photo is displayed on the ImageForm; therefore, the property PictureBoxon Form1should not be shown.

  16. In the ifblock, hide the PictureBoxby setting the propertyPictureBox.Visibleproperty to false, as shown in the following code example.

    Copy Code
    propertyPictureBox.Visible = false;
    
  17. The property DataGridcan now occupy all of Form1, so set the propertyDataGrid.Dockproperty to DockStyle.Fillin the ifblock, as shown in the following code example.

    Copy Code
    propertyDataGrid.Dock = DockStyle.Fill;
    

    When the application is using the DisplayMode.Simplelayout, all of Form1 is occupied by the property listing; therefore, the user needs a command to display the ImageFormform.

  18. In the ifblock, create a new MenuIteminstance, and then assign it to the menuViewPhotoclass member variable. Set the menuViewPhoto.Textproperty to View Photo, as shown in the following code example.

    Copy Code
    menuViewPhoto = new MenuItem();
    menuViewPhoto.Text = "View Photo";
    
  19. Associate the menuViewPhoto_Clickmethod that you created earlier with the menuViewPhoto.Clickevent. Finally, add the menuViewPhotoclass member to the menuPopup.MenuItemscollection.

  20. Verify that the complete Form1_Loadmethod looks like the following code example.

    Copy Code
    private void Form1_Load(object sender, EventArgs e)
    {
    	// Get values for control scaling
    	DisplayInfo.GetDisplayRatios(this, ref _widthRatio, ref
    _heightRatio);
    	PopulateHouseViewDataSet();
    	_propertyDetailForm = new PropertyDetailForm();
    	_propertyDetailForm.SetBindingSource(propertyBindingSource);
    	DisplayImage();
    	// In Simple mode, picture is displayed on a separate form
    	if (DisplayInfo.GetDisplayMode() == DisplayMode.Simple)
    	{
    		// Create the image form and hook up data binding
    		_imageForm = new ImageForm();
    		_imageForm.SetBindingSource(propertyBindingSource);
    		// Hide the picture box on Form1 and set the grid
    		// to occupy the whole form
    		propertyPictureBox.Visible = false;
    		propertyDataGrid.Dock = DockStyle.Fill;
    		// Add a command to display image
    		menuViewPhoto = new MenuItem();
    		menuViewPhoto.Text = "View Photo";
    		menuViewPhoto.Click += menuViewPhoto_Click;
    		menuPopup.MenuItems.Add(menuViewPhoto);
    }
    }
    
    Note:
    For simplicity, the Form1_Loadmethod and the rest of the lab code focuses on providing easy-to-read code that is related to managing device differences rather than focusing on code optimization at the cost of readability. The Form1_Loadmethod is one such case where this is true. If desired, you can add a slight resource optimization to the Form1_Loadmethod by adding an elseblock to the existing ifstatement block, so the DisplayImagemethod only gets called when the layout is not DisplayMode.Simple.

    The DisplayImagemethod updates the PictureBoxon the main form, so the image that is displayed corresponds to the currently selected property. When the application is using the DisplayMode.Simplelayout, the PictureBoxon the main form is hidden; therefore, the call to the DisplayImagemethod has no visible effect on the application, but it consumes some resources by creating a BitMapinstance. Although changing the Form1_Loadmethod to not call the DisplayImagemethod saves some resources, the savings is not that significant because the Form1_Loadmethod is only called once at the beginning of the application. An even better optimization is to modify the DisplayImagemethod itself, so it only updates the image displayed in the PictureBoxwhen the layout is DisplayMode.Simple.

  21. Locate the AdjustFormLayoutmethod.

    Locate the last three lines in the AdjustFormLayoutmethod. They set the size of the propertyDataGridand propertyPictureBoxcontrols and the location of the propertyPictureBoxcontrol. These assignments are only necessary for the DisplayMode.Portraitand DisplayMode.Landscapelayouts because, in the DisplayMode.Simplelayout, the propertyPictureBoxis hidden and the propertyDataGridis set to fill the form.

  22. To prevent these assignments from happening when using the simple layout, place the three statements in an ifstatement block that checks that the dispModevariable is not set to DisplayMode.Simple.

    With the new ifstatement block added, the last several lines of the AdjustFormLayoutmethod look like the following code example.

    Copy Code
    	ScaleFormControls(ref gridSize, ref pictureBoxLocation, ref
    pictureBoxSize);
    	if (dispMode != DisplayMode.Simple)
    	{
    		propertyDataGrid.Size = gridSize;
    		propertyPictureBox.Location = pictureBoxLocation;
    		propertyPictureBox.Size = pictureBoxSize;
    }
    }
    
  23. Locate the ScaleFormControlsmethod in the Form1class.

    You need to modify the ScaleFormControlsmethod so the DataGridand PictureBoxare only scaled when the application is using a DisplayMode.Portraitor DisplayMode.Landscapelayout.

  24. In the ScaleFormControlsmethod, add an if/elsestatement block immediately following the call to DisplayInfo.GetDisplayMode.

    The ifcondition tests whether the dispModevariable has a value of DisplayMode.Simple. The else block contains all of the remaining code in the method except the call to the ScaleGridMembersmethod. The call to the ScaleGridMembersmethod is just after the end of the else block because the columns within the DataGridneed to be appropriately sized for all display layouts.

  25. Add a line to the true part of the ifblock that divides the propertyDataGrid'swidth by the gridDesignWidthconstant and assigns the result to the gridWidthRatiovariable.

    The completed ScaleFormControlsmethod looks like the following code example.

    Copy Code
    void ScaleFormControls(ref Size gridSize, ref Point
    pictureBoxLocation, ref Size pictureBoxSize)
    {
    	float gridWidthRatio = 0;
    	DisplayMode dispMode = DisplayInfo.GetDisplayMode();
    	if (dispMode == DisplayMode.Simple)
    	{
    		// In default layout, the size of the grid is not
    		// adjusted but
    		// the grid may still be a different size then at 
    		// design-time
    		// because in default layout, the grid is set to fill 
    		// the form
    		gridWidthRatio = propertyDataGrid.Size.Width /
    gridDesignWidth;
    
    }
    	else
    	{
    		gridSize.Width = (int)(gridSize.Width * _widthRatio);
    		gridSize.Height = (int)(gridSize.Height * _heightRatio);
    		pictureBoxSize.Width = (int)(pictureBoxSize.Width *
    _widthRatio);
    		pictureBoxSize.Height = (int)(pictureBoxSize.Height *
    _heightRatio);
    		gridWidthRatio = gridSize.Width / gridDesignWidth;
    		if (dispMode == DisplayMode.Portrait)
    			// portrait
    			pictureBoxLocation.Y = (int)(pictureBoxLocation.Y *
    _heightRatio);
    		else if (dispMode == DisplayMode.Landscape)
    			// landscape
    			pictureBoxLocation.X = (int)(pictureBoxLocation.X *
    _widthRatio);
    }
    
    	// Must always adjust grid members to correspond
    	// to the grid's current width
    	ScaleGridMembers(propertyDataGrid, gridWidthRatio);
    }
    
To test the final application on the square-screen emulator
  1. In the Target Devicelist in Visual Studio, select Windows Mobile 5.0 Pocket PC Square Emulatorif it isn't already selected.

  2. Click Debug| Start Debuggingto start the application.

  3. After the application starts, notice that only the data grid appears on the Home Viewscreen, as shown in Figure 23.

    Figure 23. The application displaying the Home View in simple mode

  4. Click Menu| View Phototo display the selected property's picture on the ImageForm, as shown in Figure 24.

    Figure 24. The application ImageForm

  5. Click Doneto close the ImageFormscreen and return to the Home Viewscreen.

  6. Click Menu| Exitto close the application.

To test the final application on other emulators
  1. In the Target Devicelist, select Windows Mobile 5.0 Pocket PC Emulator.

  2. Click Debug| Start Debuggingto start the application.

  3. Observe the behavior of the application in both portrait and landscape modes as you did in previous exercises. Notice that the property listing and property photo are still displayed on the Home Viewscreen as before. Also notice that the Menu| View Imagecommand is not available in these modes because it's not needed.

  4. If time allows, try running the application on the various other emulators and note that it behaves appropriately each case.

Conclusion

In this lab, you performed the following exercises:

  • Identifying device characteristics

  • Adapting to device capabilities

  • Supporting both landscape and portrait displays

  • Adding high-resolution support

  • Supporting square and other displays

Terminating an Application That Is Running on a Device or Emulator

This section describes how to terminate an application that is running on a device or emulator. This is useful for cases where an application has been started without having the debugger attached and the application needs to be terminated so a new copy of the application can be deployed. You will terminate the application by using the Remote Process Viewer remote tool in Visual Studio.

Before you can terminate a process, you need to know the name of the executable file. In most cases, this is the same name as the Visual Studio project. If you are uncertain about the name of the executable file, you can find it in the project's properties.

To terminate an application that is running on a device or emulator by using the Remote Process Viewer remote tool
  1. In Visual Studio, click Project| xxx Properties, where xxxrepresents the name of the current project.

  2. In the Project Propertiesdialog box, click Configuration Properties| Linker| General| Output Filefield. Note the value of the Output Filefield. This is the name that the executable file will be running on the device or emulator.

  3. Close the Propertiesdialog box.

    Now, you can terminate the process.

  4. On the desktop computer, click Start| Microsoft Visual Studio 2005| Visual Studio Remote Tools| Remote Process Viewer.

  5. When prompted by the Select a Windows CE Devicedialog box, select the emulator or device where the application is running, as shown in Figure 25, and then click OK.

    Figure 25. Select a Windows CE Device dialog box

  6. After the connection to the emulator or device completes, select the application that you want to terminate in the top pane of the Remote Process Viewer, as shown in Figure 26.

    Figure 26. Selecting the application to terminate

    You may need to widen the Process column (the leftmost column) to fully view the process names.

  7. In Windows CE Remote Process Viewer, click File| Terminate Processto terminate the process.

    Note:
    Be certain that the correct process is selected before you click Terminate Process. Terminating the incorrect process may render the device or emulator unusable, requiring it to be reset before you can use it again.
  8. Verify that the process is terminated by selecting Target| Refresh. Scroll to the top pane of Windows CE Remote Process Viewer again. If the application name still appears, the process was not terminated, and you need to repeat these steps.

Note:
Most processes terminate in one try; however, depending on the state of the application, terminating a process occasionally takes two attempts.

Setting Up Your Computer

The following lab files are required to set up your computer to run this HOL:

  • Pre-existing Visual Studio 2005 project, code, and data files.

Note:
Only if you are working on this HOL outside of a Microsoft conference will you need to install the data files.

To install these files to the correct path, download and run the following installation program:

MEDC06_HOL311.msi

Note:
If you used an emulator in a previous HOL, you should do a hard reset on the emulator before starting this HOL. (On the emulator, click File| Reset| Hard.)
Note:
If you receive an error during deployment that indicates that the process or file is in use, this means that the program is still running on the emulator and must be closed before a new copy can be deployed and run. This error may appear anytime in the lab that you deploy the emulator. For more information about exiting a running application, see Terminating an Application That Is Running on a Device or Emulator in this HOL.