Click to Rate and Give Feedback
Related Articles

Developers often struggle with versioning workflows and their related classes. Matt Milner discusses the core issues related to workflow versioning and provides recommendations for making changes to workflow definitions, activities, and workflow services.

Matthew Milner

MSDN Magazine May 2009

...

Read more!

This column shows you how to secure the .NET Services Bus and also provides some helper classes and utilities to automate many of the details.

Juval Lowy

MSDN Magazine July 2009

...

Read more!

Use Test-Driven Development with mock objects to design object oriented code in terms of roles and responsibilities, not categorization of objects into class hierarchies.

Isaiah Perumalla

MSDN Magazine June 2009

...

Read more!

Udi Dahan explains how his team identified and overcame unforeseen problems while developing a large-scale software + services trading application.

Udi Dahan

MSDN Magazine April 2009

...

Read more!

.NET RIA Services provides a set of server components and ASP.NET extensions such as authentication, roles, and profile management. We’ll show you how they work.

Jonathan Carter

MSDN Magazine May 2009

...

Read more!

Popular Articles

We introduce you to the benefits of building composite applications with the Composite Application Guidance for WPF from Microsoft patterns & practices.

Glenn Block

MSDN Magazine September 2008

...

Read more!

Now you can perform efficient, sophisticated text analysis using regular expressions in SQL Server 2005.

David Banister

MSDN Magazine February 2007

...

Read more!

This article introduces 10 development tools that can increase your productivity, give you a better understanding of .NET, and maybe even change the way that you develop applications. The tools covered include NUnit to write unit tests, Reflector to examine assemblies, FxCop to police your code, Regulator to build regular expressions, NDoc to create code documentation and five more.

James Avery

MSDN Magazine July 2004

...

Read more!

See how routed events and routed commands in Windows Presentation Foundation form the basis for communication between the parts of your UI.

Brian Noyes

MSDN Magazine September 2008

...

Read more!

James Avery does it again with his popular list of developer tools. This time he covers the best Visual Studio add-ins available today that you can download for free.

James Avery

MSDN Magazine December 2005

...

Read more!

Mobility
Optimize Your Pocket PC Development with the .NET Compact Framework
Dave Edson and John Socha-Leialoha

This article discusses:
  • Tips for making programming in the .NET Compact Framework environment easier
  • Tricks for making your Pocket PC-based apps run faster
  • Important .NET Compact Framework classes
  • .NET Compact Framework windowing issues
This article uses the following technologies:
.NET Compact Framework, Win32, C#
Code download available at: NETCompactFramework.exe (270 KB)
Browse the Code Online
Programmers get away with a lot today. With .NET, at last there is a framework that allows for really easy application development. Memory is managed with so little effort from the developer that we can easily abuse it. All the neat controls, forms, windowing systems, and GDI+ capabilities make it so easy. Easy, that is, until you have to write for the Pocket PC, a 200MHz platform with achingly slow graphics (read: no acceleration), no hard drive, and only 32MB of RAM, of which you can really only use about 2 or 3MB. Add to the hardware limitations the sinking feeling you get when you dive into the .NET Compact Framework and discover that some of your favorite features are not implemented. Suddenly your dream of writing that squeaky clean C# killer app turns into a nightmare.
Don't despair. The .NET Compact Framework really can be used to write great code and great applications. As long as you take a few things into consideration and are willing to bend a rule or two, you can have your performance cake and eat it too. We have written many applications using C# for the Pocket PC, resulting in polished, slick apps that are small and fast.
This article is divided into two main sections: goodies and optimization. In the goodies part, we will go over some neat tricks that make our lives as programmers easier, using the .NET Compact Framework. In the optimization section, we will discuss techniques to increase performance, decrease load time, and decrease memory footprints. Sample code will be provided to help you turn your app into something small and fast.

Essential Goodies and Our Test Bench
When you fire up Visual Studio® .NET to build our initial application, you'll need to make sure to add these lines of code in the main form's constructor, right after the call to InitializeComponent:
#if DEBUG
    MinimizeBox = false;
#else
    MinimizeBox = true;
#endif
This lets you actually close the app rather than just minimizing it, which can come in very handy when testing outside the debugger. The next important task is to unearth the full power of the device for which you are programming.
The .NET Compact Framework is certainly true to its name—it sure is compact. Thankfully, interop services are included, and as a result you can call any of the Win32® CE APIs on the device. Since many of these APIs require a window handle, you need to get one. Until version 2.0 of .NET Compact Framework is released (which resurrects the Handle property), use these lines of code to get the hWnd:
control.Capture = true;
IntPtr hwnd = Win32.GetCapture();
control.Capture = false;
See the sidebar "The Windows CE Namespace" for the Win32 class.
Now that the Win32 API is back in your grasp, there is another very handy use of that hWnd. You can subclass your own window with a Win32 DLL written with eMbedded Visual C++® 4.0 and play hardball. But there is something to keep in mind: the interop services do not keep a DLL loaded in memory. Deep inside the bowels of P/Invoke is a LoadLibrary/FreeLibrary pair. If you want your DLL to subclass your app (or, excuse me, any app on the system), that DLL needs to stay loaded in memory until you are ready to let it go. There is a nice solution to this problem: just call LoadLibrary on the DLL when you start, and then call FreeLibrary on the DLL when you are finished. The reference count will be bumped up a notch, and P/Invoke's LoadLibrary/FreeLibrary pair will become benign.
Figure 1 MSDN Test Bench 
A lot of different topics are going to be covered in this article. We have written a Test Bench program (shown in Figure 1) that integrates many of the concepts discussed. It incorporates the Win32 class covered in the sidebar "The Windows CE Namespace" as well as the BaseControl class discussed later in this article.

Bad, Wicked Dialogs
Users and developers unaware of dialog behavior in the .NET Compact Framework can end up in La-La Land when they open a modal dialog. Dialogs in the .NET Compact Framework aren't really dialogs in the normal sense. Rather, they're simply new forms that appear on top of existing forms, but don't return control to the caller until you close the form. If you use code like this to display your dialog
  BadDialog test = new BadDialog();
   test.ShowDialog();
the dialog will appear as a top-level form. When the user switches away from your program, the fun begins. Eventually they want to get back to your app, and they go to the System | Settings | Memory | Running Programs page, where they see both your main app and the dialog box listed. If the user clicks on the top-level app instead of the dialog, the main app window will be displayed, but will be inactive as it is waiting for the dialog to be closed.
To see this happen, click the Bad Dialog button on the Test Bench application. Now go into the list of running programs from the Settings screen and activate the Test Bench application (see Figure 2). If you tap on any of the buttons, they'll just beep, as this window is disabled. You can't even close it. So your users respond in the only way they know how: a clicking fit (actually, a tapping fit on a mobile device). The way out of this pickle is to go back to the list of running programs and activate the Bad Dialog item. Just to pour salt into the wound, once you close the dialog, another application may pop up, since the z-order of the windows could have been changed while you were switching from program to program.
Figure 2 Confusing Information 
To fix these problems, as well as a few others related to the existence of multiple forms, we created a Dialogs class with a static member called ShowDialog. Here's what it does:
  • Hides the parent form in the Running Programs List by setting its caption to an empty string.
  • Sets the caption of the dialog to the same name used by the parent form, preserving the name you see in the Running Program List, no matter which dialog is topmost.
  • Traps the Activated and Closed events of the new dialog so you can keep track of which form is the "topmost" form.
  • Calls ShowDialog for the dialog.
  • Activates and brings the "topmost" form to the top whenever any of the "parent" forms is activated.
This whole process sometimes results in another application being visible momentarily when you close a modal dialog, but other than that, everything works as a user would expect. You can see how this enhanced version of ShowDialog works by clicking on the Dialog Fix button in the Test Bench application. Notice that the caption on the dialog is the same as the main form, and only one form shows up in the Running Programs List.

Chilling Out the Context Menu
Tap and hold on a typical Pocket PC-based application, and you get those dancing dots followed by a context menu. To the user, it's divine. To the programmer, it's annoying because you don't receive the MouseDown event. This means that you don't have a chance to do some pre-context menu operations, such as disallowing the context menu in the first place or changing a selection. Getting around this behavior involves playing a few tricks on the runtime. Normally, you would just set the ContextMenu property of a control to associate it with a context menu for when a user taps and holds. In our solution, we don't set the ContextMenu property of the control; instead we mimic the code built into the Control class to handle the MouseDown event and display the menu. To make this as transparent as possible for the programmer, we developed a new base control class cleverly named BaseControl. It encapsulates a lot of the behavior we want available to our custom controls. See Figure 3 for a short list of these features. The key to banishing the default behavior and replacing it with our own is to override the ContextMenu property. This way the Control.ContextMenu property is still null, while BaseControl.ContextMenu contains the information we need.

Feature Description
Handle property Implements Handle property that is missing from .NET Compact Framework controls, allowing access to the window handle
Gdi Provides support for using the Gdi class to draw; there are a number of methods and properties that help with this task
Buffered drawing Supports drawing to an off-screen bitmap instead of the screen, then copying changes to the screen; helps eliminate flicker, but does require extra memory
Context menu Allows you to receive the MouseDown event immediately when you have a context menu
Figure 4 shows the four methods of BaseControl that get the work done: OnMouseDown, CheckContext, ShowContext, and RecognizeGesture. Your own custom control can override the OnMouseDown method if you need to change a selection or do some other action. The CheckContext method calls OnBeforeContextPopup, which in turn fires a BeforeContextPopup event. The event handler then has a chance to change or cancel the context menu, or do other application-specific things. The RecognizeGesture method does the actual work of making the dancing dots appear. ShowContext displays the context menu.
protected override void OnMouseDown(MouseEventArgs e)
{
    base.OnMouseDown(e);
    CheckContext(e, this, this.Handle);
}

protected void CheckContext(
    MouseEventArgs e, Control control, IntPtr hwnd)
{
    // Tap and Hold: Overrides the built-in implementation to allow 
    // you to receive MouseDown before the context menu is displayed.
    m_justDidContext = false;
    if (m_context != null)
    {
        // Give a chance to cancel the context menu
        // (or change the menu that we'll show).
        ContextPopupEventArgs eContext = 
            new ContextPopupEventArgs(e.X, e.Y);
        OnBeforeContextPopup(eContext);     // Give subclass a chance to 
                                            // cancel or change context
                
        bool fShow = false;
        if (eContext.Cancel == false)
            fShow = RecognizeGesture(hwnd, e.X, e.Y);
        if (fShow) ShowContext(control, eContext);
    }
}

protected void ShowContext(
    Control control, ContextPopupEventArgs eContext)
{
    if (m_context != null)
    {
        m_justDidContext = true;

        OnContextPopup(eContext);
        m_context.Show(control, new Point(eContext.X, eContext.Y));
        OnContextClose(eContext);
    }
}

protected virtual bool RecognizeGesture(IntPtr hwnd, int x, int y)
{
    SHRGINFO info = new SHRGINFO();
    info.cbSize = Marshal.SizeOf(info);
    info.ptDown = new Point(x, y);
    info.dwFlags = SHRG_RETURNCMD;
    info.hwndClient = hwnd;

    int cmd = SHRecognizeGesture(ref info);

    return (cmd == GN_CONTEXTMENU);
}
Figure 5 Context Menu Trick 
On the Test Bench program, tap the Context Menu button and you will see the screen shown in Figure 5. The top grey box control is a normally created control. Tap on it and the listbox underneath will show the relevant events. As explained, if you tap and hold, no mouse down event happens. The lower half of the screen uses a control that employs our tricks. This control behaves just like the normal control, except you get that oh-so-important mouse down event at the very moment the user touches the screen.

Designable Custom Controls
Designing custom controls for the .NET Compact Framework is not quite as easy as it is for the desktop. It would be nice to be able to use the designer to create a custom control, and then use the new control while designing your application. On the desktop this all works seamlessly because the code behind the desktop System.Windows.Form.Control object has all the designer support code built in. Microsoft.WindowsCE.Forms.Control doesn't have this code because it would eat up memory.
There is a little trick you can do to make this happen, however. When designing a new custom control, start with a form instead of a control. Now you can use all the designer tools to build your custom control. Of course, there is a price for this, but it isn't too high: when using the designer for your application (not the control), you cannot add your custom control to the designer's toolbox because you've created a form, not a control. Therefore, you will need to create an instance of the "control," using code like this:
MyControl = new MyCustomControl();
Controls.Add(MyControl);
   MyControl.Location = new Point(x, y);
   MyControl.Size = new Size(dx, dy);
   MyControl.Visible = true;
Notice that we're setting both the location and the size. When you are using a form as a control, the .NET Compact Framework will automatically set its size as appropriate for using the full screen. To get around this, you'll have to set the size yourself.
There is one little problem, however. In some cases, adding a custom control that is actually a form will cause extra flicker in the caption at the top of the screen, as it first changes to show the caption from the new form and then changes back. Getting around this involves undoing our trick. We need to change the base class back to a control again! To let the control flip-flop on whether it wants to be a form or a control, you can add a conditional compilation constant and modify the class definition for each custom control you create based on this form trick.
Figure 6 DESIGN Conditional Constant 
Figure 6 shows the conditional constant called DESIGN, which is only set in the debug version of the compilation. Modify the class definition for your custom control (form) to look something like this:
   // DESIGN is only set in Debug builds
   #if DESIGN
       public class MyCustomControl : 
          System.Windows.Forms.Form
   #else
       public class MyCustomControl : 
          System.Windows.Forms.Control
   #endif
Figure 7 Custom Control 
If the DESIGN constant isn't defined (which it shouldn't be for the release mode), your custom control will be compiled as a control instead of as a form. You can keep the DESIGN constant defined for debug mode and test in that mode. But if you want to, you can always remove it for testing your code, then add it back in so you can design the form again. If you remove and add it, you might need to recompile your application before Visual Studio recognizes again that it can design the form.
In the Test Bench application, tapping on the Custom Control button brings up a dialog with the custom control in it (see Figure 7). If you go to the source code for the Test Bench, you will see the MyCustomControl class in the Tests folder, which you are able to edit from the designer (see Figure 8).
Figure 8 MyCustomControl 

Optimization
Writing small, fast code is always a good idea, but it's critical when writing for the .NET Compact Framework. You just don't have a whole lot of memory or speed available. At design time, you need to think about what code will be executed and how your data structures are going to be used. Since memory is at a premium, it's important to avoid making copies of data. And most importantly, your code should only create data when it is needed, and discard it when finished.
Another issue to take into consideration is when to use .NET code and when to use Win32 code. There are times when it is much faster and easier to use Win32 code (really!). You will be glad to know that most of the time it is easier to use .NET code. Note, though, that we are not going to encourage you to return to the age of stone knives and bearskins just to eke a little bit better performance from your applications.
In a nutshell, the .NET Compact Framework rocks when it comes to memory management, event handling, object-oriented programming, user input, internationalization, and file I/O. The places where the .NET Compact Framework has the biggest challenges are graphics, window management, and resource management. Enormous improvements in speed and functionality may be gained by abandoning the Graphics object and going back to the Win32 GDI. When it comes to window management, .NET Compact Framework code can be tweaked to improve performance immensely. It just takes a long time to create windows. If you have a tab control with many controls across many pages, it can take eons for the tab control to initialize. This is because each and every control on every page is created at load time. Later on, we will present a replacement for the tab control class that is mainly .NET code with a sprinkling of Win32 calls that results in a tab control that loads blisteringly fast and dynamically loads or discards nonvisible pages.
One way to time your application's performance is with the Environment.TickCount property, as shown here:
   int t = Environment.TickCount;
   // <do your stuff here>
   t = Environment.TickCount - t;
Of course, nothing is that easy. Since a .NET executable is actually composed of Microsoft® intermediate language (MSIL) code, there is a just-in-time (JIT) compiler involved. The first time your function is called, it may take more time than in subsequent calls. Keep this in mind when running your tests. Also note that the emulator and the actual device can give very different opinions on the amount of time it takes to get a task done. Therefore, you will need to run all of your benchmarking tests on the actual device and not through the debugger.
Our first example harkens back to a May 1995 Microsoft Systems Journal article entitled "Grab Bag of Gotchas and Goodies for Programming in Windows." ExtTextOut is still, after all these years, the fastest way to splat text onto the screen. It can also draw with a transparent background, which labels in the .NET Compact Framework do not support (just try to put a label over a PictureBox and you'll see).
Figure 9 GDI Speed Test 
On the Test Bench program, run the GDI Speed Test. The first time you run the test, the JIT compiler will taint the results. On our device, the conventional .NET approach using DrawString took 51ms, while using the GDI method ExtTextOut took only 22ms. If you take the time to run the test a second time, you will see a tremendous improvement in speed, as shown in Figure 9.

Getting Resourceful
When it comes time to add images and text to your application, it's a good idea to use resources instead of hand-coding the text or using external files for images. Visual Studio .NET 2003 has all the tools you need to create string resources, but it lacks built-in support for managing image resources. For that you need to turn either to the ResEditor sample application that ships with Visual Studio .NET or to a third-party application. Our favorite is a free program called Resourcer for .NET that is available at www.aisto.com/roeder/dotnet. It's simple to use and comes with source code, so you can change it if you like.
The Test Bench program loads a bitmap resource into the form when you click the Resources button. Test Bench contains a class called MyResources that makes using these resources much easier. This is all you need to do to load an image:
m_image = MyResources.Icons.LoadBitmap("resTest");
You can create a string resource file simply by using the Add New Item dialog box to add a new assembly resource file. To group the resources in one place, we created a file called strings.resx in a folder called Resources. Double-click on the strings.resx file and you'll see a screen like the one shown in Figure 10. To load a string, you just do the following:
string s = MyResources.Strings["id"];
The Windows CE Namespace
To aid in writing code using the .NET Compact Framework, we've created a library of Win32 wrapper classes and .NET Compact Framework utility classes, shown in Figure A.
The current implementation of fonts in the .NET Compact Framework doesn't work very well. A glaring example of this is that you simply can't create an eight-point font on some devices. Our FontCache class takes all the pain away from fonts. It has one public method: CreateFont. There are three overloads of this method, as shown here:
FontGdi CreateFont(string Family, float Size, FontStyle Style)
FontGdi CreateFont(
    string Family, float Size, FontStyle Style, bool forceClearType)
FontGdi CreateFont(Font fromFont)
You have the option of forcing ClearType fonts even if ClearType is not selected in the Settings dialog of your device. In addition, when you ask for a font of a certain size, you get it. As you can guess, FontCache is a cache of fonts. That means that if you call CreateFont twice with the same parameters, only one instance of the actual font is created in memory. Tap the Font Test button in the Test Bench application and you will see fonts created via the Framework on the top, and fonts created with FontCache on the bottom.
The Gdi class is quite powerful. Its methods are shown in Figure B. If you use the properties of the Gdi object to change pens, brushes, and so on, then you do not need to worry about the whole SelectObject shenanigans from Win32 days. Typical usage of the Gdi object is done in the Paint event handler. The FontCache class is utilized in this example:
private void MainForm_Paint(
    object sender, System.Windows.Forms.PaintEventArgs e)
{
    using ( Gdi gdi = new Gdi (this))
    {
        gdi.TextColor = Color.Red;
        gdi.Font = FontCache.CreateFont ( "Tahoma", 12, FontStyle.Regular );
        gdi.ExtTextOut ( 100, 100, "Wardrobe Malfunction" );
    }
}


Properties Description
IntPtr ClipRegion Current Win32 clip region.
Color BackColor Current background color.
BrushGdi Brush Current brush.
FontGdi Font Current font.
PenGdi Pen Current pen.
Color TextColor Current text color.
bool Transparent Sets the background mix mode to either transparent or opaque.
Methods Description
Gdi(IntPtr hwnd)
Gdi(IntPtr hwnd, Rectangle clipRect)
Gdi(Control control)
static Gdi FromHdc (IntPtr hdc)
Constructors. Allows you to create a Gdi object in a variety of ways.
void Dispose() Disposes method to clean up resources.
PenGdi CreatePen(Color c)
PenGdi CreatePen(Color color, PenMode mode)
Creates a PenGdi object of a specified color.
BrushGdi CreateSolidBrush(Color c) Creates a BrushGdi object of a specified color.
bool DeleteObject(IntPtr obj) Deletes an object. Returns true if successful; false otherwise.
void DrawClipped(string text, int width, int x, int y) Draws text. If the text is wider than the width parameter (pixels), as much text as possible is drawn with ellipses ("...") at the end.
int DrawText(string text, Win32.RECT rect, Win32.DT format) Exact same functionality as Win32 DrawText.
bool ExtTextOut(int x, int y, string text) Exact same functionality as Win32 ExtTextOut. Draws a single line of text into the window without clipping or wrapping. This is fast.
bool ExtTextOut(int x, int y, int width, string text) Same as above function, except centered between x and x+width.
int FillRect(Win32.RECT rect, BrushGdi hbrush)
int FillRect(int x, int y, int w, int h, BrushGdi hbrush)
int FillRect(Rectangle rect, BrushGdi hbrush)
int FillRect(Rectangle rect, Color color)
Fills a rectangle with the specified color.
void DrawRectangle(Rectangle rect) Draws a rectangle with the interior using the current brush and the edges using the current pen.
void FrameRect(Rectangle rect) Draws the edges of a rectangle with the current pen, leaving the interior untouched.
BrushGdi GetStockBrush(Win32.StockObjects type) Gets a stock brush from the Win32 GDI.
Size GetTextExtent(string text)
Size GetTextExtent(string text, int width, out int[] extents, out int maxFit)
Measures the size of a string, in pixels, using the current font. The text that you want to measure and the maximum width that you'll allow are passed to the method as parameters. On exit, the extents parameter is set to an array of character positions for the string, and the maxFit parameter is set to the maximum number of characters that will fit in the width. The method returns the width and height of the string.
Size GetDrawTextSize(string text, int width, Win32.DT format) Returns the size that DrawText will calculate for text with the currently selected font.
bool DrawLine(int x1, int y1, int x2, int y2)
void DrawLine(int x1, int y1, int x2, int y2, Color color)
Draws a line.
bool Polygon(Point[] points) Same as the Win32 Polygon API.
bool Polyline(Point[] points) Same as the Win32 Polyline API.
IntPtr SelectObject(IntPtr obj)
PenGdi SelectObject(PenGdi pen)
BrushGdi SelectObject(BrushGdi brush)
Same as the Win32 SelectObject API.

Class Description
Win32 A wrapper around a variety of functions in Win32
Registry A collection of functions that make it easy to access and edit the Registry
Gdi A high-speed replacement for the Graphics object
PenGdi A type-safe wrapper for the GDI Pen Handle
FontGdi A type-safe wrapper for the GDI Font Handle
BrushGdi A type-safe wrapper for the GDI Brush Handle
FontCache A turnkey font solution that creates and manages fonts with minimal system resource usage
As we mentioned before, using image resources requires the use of an external resource editor. If you're using Resourcer, you can select Add File from the Add menu, enter the name of the image resource to be added, then select the file. If you run the sample application and click on the Resource Test button, you'll see both a string and an image loaded from the resource file.
Figure 10 Adding a String Resource File 
If you are writing a commercial application, there are many reasons to put your resources into a separate DLL. The most important is that you can offer various skins. If you can offer users a variety of appearances for the application, you can increase your potential customer base. We won't go into details of how to write a skinnable application, but we will assume that strings, bitmaps, and positional information all need to go into a DLL that can easily be swapped out with another that contains a different skin.
Dynamically loading a .NET DLL with the .NET Compact Framework and getting the resources out of it is not pleasant. Even if it were, you would be fast asleep by the time your resources were loaded. There is also an annoying behavior with .NET resources: if you load an image from a .NET resource, and then call Dispose, the image is gone for good. If you try to load it again from the .NET resource, the resource loader will give you back a valid Image object that won't draw itself. The only way to get that image to recache itself is to create a new instance of the resource loader (which takes time). So let's just walk away from those resources altogether and start from scratch.
Before we talk about loading bitmaps, we need to talk about rendering them. The Win32 BitBlt function still rules the world when it comes to speed—as long as you are using a device-dependent bitmap (DDB), that is. If you try to Blt out to a device-independent bitmap (DIB), you take a huge speed hit.
Inside the system directory of your Pocket PC device is a DLL that decompresses all sorts of image formats: JPG, PNG, and GIF, just to name a few. We take advantage of this functionality in a C++ DLL we wrote that can load an image resource from a DLL and return to us the information as a DDB. The DLL has two exposed functions:
HBITMAP LoadBitmapFromFilename (HDC hdc, LPCTSTR szFileName);
HBITMAP LoadBitmapFromResource (
    HDC hdc, DWORD dwResourceID, LPCTSTR pcszClass, HMODULE hModule);
The first parameter for both of these functions is a handle to device context (HDC). We will use our eponymously named Win32 class to get the HDC of the current form, and pass that into these functions. The functions then use the HDC passed in to figure out how to return a DDB to your application. The first function is easy. The second function can be cleared up with some code snippets. Here is the code in the RC file of a C++ resource DLL:
1001    PNG    DISCARDABLE    "msdn.png"
And here is the code that would load this into your application:
[DllImport("ImageLoader.dll", CharSet=CharSet.Unicode)]
public static extern IntPtr LoadBitmapFromResource(
    IntPtr hdc, uint dwResourceID, string pcszClass, IntPtr hModule);
...
hInstance = Win32.LoadLibary ( stringDLLName );
if (hInstance != IntPtr.Zero)
{
    IntPtr hdc = Win32.GetDC ( this.Handle );
    hbmp = LoadBitmapFromResource ( hdc, 1001,  
           "PNG", hInstance );
    Win32.ReleaseDC ( hwnd, hdc );
    Win32.FreeLibrary ( stringDLLName );
}
You will find that this loads a bitmap quite quickly. And since the JPG, PNG, and GIF formats are supported, your resource DLLs can be quite small. In addition to images, you can also use the Win32.LoadString method to stuff language-specific information or even positional information as strings.
Figure 11 Resource Test 
In our Test Bench application, tap the Resource Test button to see a comparison (see Figure 11). In the Resource Test screen, tap the Load button to load a bitmap from a resource DLL using the code you just saw and using a normal .NET resource call. Each piece of code loads the resource, draws it, and then discards it. The first time you run the test, you will see a stunning difference in speed. Subsequent runs are not as impressive, yet there is still a difference. For example, the next run we did resulted in a load time of 30ms for the .NET Compact Framework and 7ms for our DLL.

Load Only What You Need; Chuck What You Don't
Good optimization starts with good memory management. Our favorite method in programming .NET is Dispose. Since we do not live in the blissful world of endless memory, it is important when writing your code to think about the resources it uses. For each and every form, you want to add code for when it is activated and deactivated, as shown in the following:
protected override void OnActivated(EventArgs e)
{
    base.OnActivated (e);
}

protected override void OnDeactivate(EventArgs e)
{
    base.OnDeactivate (e);
}
In these functions, you have to be sure to load and discard anything that isn't critical to the application. This is where we load and discard our bitmaps.
The same mentality goes for objects that you create and use. Any time you can free up objects when you are not using them any more, you should let them go. And everything should be created on the fly unless it is absolutely necessary for the app's well-being. This includes the forms themselves. Forms and the controls in them take up memory. When you close down a form, dispose of the form as well.
The using keyword in C# is an excellent aid for keeping you on the disposal track. Take a look at this example:
using ( MyClass thing = new MyClass ())
{
    // Do something interesting here
}
Inside the curly braces the thing object is valid. Once program control leaves the braces, the Dispose method of thing is automatically called and any resources used by the instance of MyClass are released (although the garbage collector will still be responsible for releasing the memory occupied by the thing itself). Of course, your MyClass object must support the IDisposable interface for this to work.
Solid application architecture makes this scenario easier to implement. One paradigm of programming is known as the Mediator Model. In a nutshell, apps written in accordance with the Mediator Model are arranged so that no object knows of any objects other than those directly underneath it. Objects have no idea about their parents, and they have no idea about siblings. Communication with parent objects is accomplished solely via events, and communication with direct descendants is accomplished using methods. Keeping true to this model makes it very easy to prune off entire sections of an object tree dynamically when they are not used, and makes your memory management easier. For example, let's say your application creates an object A which itself creates and uses an object B, which in turn creates and uses an object called C.
When that part of your application is no longer needed, the top-level object A simply calls B.Dispose. B.Dispose then calls the Dispose method of the C object. As a result, all of the resources from A down are removed. If you end up reusing this code in other apps, or you move it around in your current app, as long as you stick to the rules of the Mediator Model, your initialization and cleanup of objects will be robust.
In addition to keeping the overall memory footprint small, another reason to load only what you need is to improve application load time. Every unnecessary form, bitmap, or database loaded and cached away makes for a longer load time. Since Windows® CE is an instant-on type of operating system, consumers will expect the same from their applications.
Threads are your friend when it comes to reducing load time. You can use them to build up nonessential structures while the main app is doing essential activities, such as checking for registration, logging in, displaying a splash screen, or letting the user browse a main screen. If your program has many features available from a toolbar or menu, you could load the optional features in a thread, and grow or enable the menu or toolbar to show more features as the background thread is finished loading.

Putting It All Together—the TabControlEx Class
Now it's time to put together a lot of the concepts we've discussed. TabControl in the .NET Compact Framework is packed with problems. The biggest problem is that all of the pages and their controls are loaded at startup. This means that there is a long load time before the tab control comes up, and lots of memory is used. We've written a new class, which we cleverly call TabControlEx. It's a tab control built from scratch that allows for pages to be loaded only when the user clicks on the tab. TabControlEx also allows for the page to be discarded when the user clicks on another tab. The pages will automatically resize if the Input Panel appears or disappears. There are also some other nice goodies, such as better control over the visuals. See Figure 12 for a list of the properties and methods associated with the TabControlEx class.

Property Description
AutoSize Setting this property to true (default) will let the tab control size itself to use the entire client rectangle of the parent form. It will also resize itself and the tab pages whenever you show or hide the input panel. Note that you must set the Form property for this to work.
Form Set this property to the parent form if you'd like the tab control to use the entire client area of the parent form and to resize automatically when the input panel is shown or hidden.
InputPanel Provides access to the InputPanel object being used by this tab control, if any. Setting the Form property will create an InputPanel object if the Form doesn't already have one.
PageBounds The size and location of the area available for the pages of the tab control.
SelectColor The color that will be used for the background of the currently selected tab.
SelectedControl The Page control for the page that is currently visible.
SelectedPage Gives you direct access to the control for a specific page.
SelectedIndex The index of the selected page or -1 if no page is selected or there are no pages.
TabPages The collection of pages assigned to the control. The controls for each page aren't actually loaded until you select the tab for that page.
TabAlign Determines where the tabs will be drawn, along with TabPosition.
TabPosition Determines where the tabs will be drawn, along with TabAlign.
InputPanelVisible Allows you to see whether the input panel is visible on the screen.
Method Description
DisposeOtherPages Disposes all the pages except for the one you indicate, which frees them from memory.
LoadPage Forces a specific page to be loaded, even if it's not visible.
The biggest difference with TagControlEx is that you don't create your pages and add them to a collection. Instead, you add the types of pages to the collection:
m_tab.TabPages.Add("Tab Text", typeof(MyPage));
The TabControlEx class has a private method called LoadPage that uses this type information to create an instance of the control. Inside the LoadPage method is the code that is responsible for creating the actual object:
private Control LoadPage(Type type, TabPageEx tab) {
    ...
    ConstructorInfo constructor = type.GetConstructor(new Type[] {});
    Control page = (Control) constructor.Invoke(null);
    ...
    return page;
}
Using reflection to get access to the default constructor and invoking it is an elegant means of creating different kinds of objects on the fly with one piece of code.
The LoadPage method contains some code that attempts to get an IPage interface (see Figure 13) from the control, and then calls the InitPage method:
IPage p = page as IPage;
if (p != null) p.InitPage(this);
using System;

namespace WinCE
{
    public interface IPage
    {
        void InitPage(TabControlEx tabs);
        bool CanResize();
    }

    public interface IPageActivate
    {
        void Activated();
        void Deactivated();
    }

    // This is an optional interface that can be implemented by 
    // TabPageStyled pages if they want their own toolbar and/or menu 
    // bar.
    public interface IPageToolbar
    {
        ToolbarSection[] Sections(MyToolbar toolbar);
    }
}
You would implement the IPage interface for two reasons. First, you might want to do some initialization once your control is loaded that requires communicating with the rest of the application. The InitPage method has a single parameter, a pointer to the TabControlEx object. If your page needs to communicate with other pages on the tab, you can use the TabPages collection to find the other control if it's loaded. You can also register to receive the PageLoadedEventHandler event so you can interact with other controls after they're loaded. Finally, you could create a subclass of TabControlEx that has some extra properties or methods that your pages will use to interact with the rest of the application.
Second, not all pages will want to be resized when the input panel becomes visible. If this is the case, you can have the CanResize property of the IPage interface return false. The default behavior, resizing your page, will happen if you return true for your implementation of this property.
Sometimes you might want to know when your page becomes active or inactive so you can, for example, update values based on other changes in the application. The TabControl in the .NET Compact Framework doesn't provide an easy way to get such notification. You can get this notification very easily in your page control by implementing the IPageActivate interface (see Figure 13), which contains just two methods: Activated and Deactivated. These methods will be called only when the specific instance of your control is activated or deactivated. You can get the same information for all pages, instead of just one, using the TabControlEx's SelectedIndexChanged event. Generally when a page needs to know when it becomes active or inactive, using IPageActivate is easier. But when you want to monitor all pages from your application, SelectedIndexChanged would definitely be better.
In our Test Bench application, tapping on the Tab Control button brings up the tab control test dialog. The constructor for the TabTest object is shown in Figure 14.
public TabTest()
{
    // Required for Windows Forms Designer support
    InitializeComponent();
    
    // Build our TabControlEx
    m_tab = new TabControlEx();
    m_tab.Location = new Point(20, 20);
    Controls.Add(m_tab);
    m_tab.Visible = true;
    m_tab.Form = this;
    
    // Add the *types* of our pages
    m_tab.TabPages.Add("Test", typeof(MyCustomControl));
    m_tab.TabPages.Add("Button", typeof(MyButton));
}

Adding Toolbar Buttons to TabControlEx
The final optional interface for your tab pages provides something that is really useful, but is difficult to implement using the tab control in the .NET Compact Framework. Let's say you have a menu bar and you want to have some toolbars that are specific to each page of your tab control. With our TabControlEx it's really simple. You'll need to add an instance of MyToolbar to your form instead of Toolbar. MyToolbar is a subclass of Toolbar that supports the concepts of toolbar sections, which are toolbar buttons that can be shown or hidden as a group. The IPageToolbar interface in Figure 13 has a single method, which returns a list of toolbar sections. Figure 15 shows the code from our Test Bench sample application that sets up a couple of toolbar icons on the screen.
public ToolbarSection[] Sections(MyToolbar toolbar)
{
    if (!UseToolbar) return null;

    if (m_tbrSections == null)
    {
        ToolbarSection section = toolbar.CreateSection();

        Icon cancel = LoadIcon("cancel.ico");
        Icon accept = LoadIcon("accept.ico");
        section.Add(cancel, "day").Style = ToolBarButtonStyle.PushButton;
        section.Add(accept, "accept").Style = 
            ToolBarButtonStyle.PushButton;
        m_tbrSections = new ToolbarSection[] { section };
    }

    return m_tbrSections;
}
The code in the IPageToolbar.Sections method creates a new toolbar section if this is the first time that this method is called. We then add two icons to this section and return it. LoadIcon is just a helper function, as shown here:
private Icon LoadIcon(string name)
{
    string path = Path.Combine(Utility.HomePath, name);
    usin(Stream stream = File.OpenRead(path))
    {
        return new Icon(stream);
    }
}
LoadIcon gets the Utility.HomePath property, which is a one-liner that wraps up this tough-to-remember tangle of characters:
public static string HomePath
{
    get 
    { 
        return Path.GetDirectoryName(
            Assembly.GetExecutingAssembly().GetName().CodeBase); 
    }
}
Run the Test Bench sample and choose the Toolbar Test button. You can jump back and forth between the two tabs and see how the toolbar buttons appear only for the Test page.
You may have noticed that we used the same control, MyCustomControl, for this test with a toolbar and the Custom Control test, which did not use a toolbar. The IPageToolbar.Sections method returns null if the UseToolbar property of MyCustomControl is false, which is the default. To set this to true for the toolbar test, we use a technique we mentioned earlier for communicating with pages when they're first loaded. The constructor of the ToolbarTest form is identical to the TabTest form, except for the extra code added at the end of the constructor:
public ToolbarTest()
{
    ...
    tab.PageLoaded += new 
        TabControlEx.PageLoadedEventHandler(tab_PageLoaded);
    
    // Create an instance of our toolbar needed to allow 
    // each page to have its own toolbar buttons.
    MyToolbar toolbar = new MyToolbar();
    Controls.Add(toolbar);
}
First, we register to receive the PageLoadedEventHandler event of the tab control, which allows us to set properties of the control immediately after it's been loaded. We'll use this event to set the UserToolbar property to true:
private void tab_PageLoaded(object sender, PageLoadedEventArgs e)
{
    MyCustomControl control = e.Page as MyCustomControl;
    if (control != null) control.UseToolbar = true;
}
After creating the event handler, we add an instance of MyToolbar to the form, which is a subclass of the Toolbar class that supports toolbar sections.

Conclusion
Writing applications for the .NET Compact Framework is a wonderful experience. The applications are small enough that shareware developers can once again write something on their own and sell it online to make a little bit of money. But the simplicity and small capacity of mobile devices present new challenges to programmers. Without awesome power, you have awesome responsibility. Strive from the get-go to design code that is fast, tight, and highly, highly disposable.

Dave Edson is currently wearing the hats of massage therapist, pinball machine czar, and Software Architect for Potala Software, LLC. He lives in Seattle with his wife and two kids. Every possible spare moment is spent snow skiing or wakeboarding.

John Socha-Leialoha is the Chief Software Architect for Potala Software, LLC. His past achievements include writing the Norton Commander. He lives in Seattle with his wife and son. Every possible spare moment is spent building ridiculously small, yet terrifically accurate scale models for his model railroading hobby/business.

Page view tracker