Packing List for the Pocket PC in the .NET Compact Framework

PackingList.jpg

Having moved recently,  I thought it a good idea to track the items I needed to pack.  After all, it can be a bit overwhelming to think about every item you want to pack and remembering whether or not you packed it.  Inevitably, you end up smacking yourself and saying, "How the heck could I have forgotten to pack my CD Collection?!!"  Don't worry, a  technological solution is somewhere in site. What better way to inventory items than on the pocket pc?  Consequently, I created the Pocket Packing List.  This application reads items out of an xml file and displays them as checkbox items on the main form of the application.  You can also add items to the list through the menu and save the current state of the checked off items.  There is much room for additional functionality, but it gets the job done.

CF.NET 1.1 vs. 2.0

Although the Compact Framework 2.0 has a much richer programming experience, most pocket pc's as of this writing don't have the 2.0 compact framework built into the ROM.  The pocketpc's do, however, have .NET 1.1 Compact framework built in.  Therefore I chose to develop this application using the 1.1 framework.

Xml File Format

The screen is saved in an Xml file node format.  The top node is the PackingList.  Under the PackingList is the list of packers.  Under each packer a list of category nodes, and each category node contains specific items for that category.  Items contain attributes listing the name of the item, the quantity of items, and whether or not the item is checked.  Listing 1 shows the packing list file.

Listing 1 - Xml File Containing Persistent Packing Information

<?xml version="1.0" encoding="UTF-8"?>
 <
PackingList>
   <
Packer name="Mike">
      <
Category name="Toiletries">
          <
Item name="razor" checked="False" />
          <
Item name="contacts" checked="False" />
          <
Item name="brush" checked="True" />
          <
Item name="contact solution" checked="False" />
     </
Category>
     <
Category name="Clothes">
       <
Item name="Dress Shirt" quantity="3" checked="False" />
       <
Item name="Bathing Suit" quantity="2" checked="False" />
      
<Item name="Loafers" checked="False" />
       <
Item name="Short Sleeve Shirts" quantity="3" checked="False" />
       <
Item name="Dress Pants" quantity="4" checked="False" />
       <
Item name="Blue Jeans" checked="False" />
       <
Item name="Long Sleeve Shirts" quantity="2" checked="False" />
   ...

 

The Design

The design of the application consists of four classes:  The Form (Form1), a packinglist reader/writer (PackingListReader), a dialog for adding new items (AddItemDialog), and an item class (PackingListItem).  The list is drawn on the pocket pc from methods inside the form, such as the BuildCheckList method.  The form uses the PackingListReader to read and write packers, categories and items to an Xml file.   As an afterthought, I probably would have gone with a more node-like design with classes: Packer, Category, and PackingItem.  This way each class knows how to draw and serialize itself.

ta1.gif

Figure 1 - UML Design reverse engineered from C# using WithClass

 

The Code

The Form uses the PackingListReader to read in the persistent Xml packing list and then builds the list on the screen based on the xml file in listing 1.  Below is the code for building the packing list form.  The BuildCheckList method cycles through each  packer, category, and item, respectively.  As it reads the node, the form draws the appropriate control (either label or checkbox) to the pocket pc.

 

Listing 2 - Buiding the PackingList Screen from the Packing List xml file.

private void BuildCheckList()
 {
  
// get the packers first
ArrayList list = _reader.GetPackers();

pnlPackingList.Controls.Clear();
// remove existing controls from the panel
_nextLocation = 10;
// loop through each packer and retrieve the categories for the packer
foreach
(string packer in list)
 {

// Create the packer label in big red letters
   CreateLabel(packer);

//  get all the categories for the packer
   Hashtable categoryMap = _reader.GetCategoriesAndItems(packer);

// loop through each category and retrieve the items in the category
  
foreach (string category in categoryMap.Keys)
    {

//   create the category title
      CreateTitle(category);

//  move down to the next vertical location
      _nextLocation += kControlSeparation;
      ArrayList listItems = categoryMap[category]
as ArrayList;

// loop through each item in the category and create a checkbox for the item
     
foreach (PackingListItem item in listItems)
      {
         CheckBox chkBox = CreateCheckBox(item.ItemName, item.State);
        
if (item.Quantity != "1")
          {

           //  Create a quantity label if the quantity is greater than 1 item

            CreateQuantityLabel(item.Quantity);
          }
       }

       //  move down to the next vertical location
   
    _nextLocation += kControlSeparation;
  }

}

}

 

Scrolling on the Pocket PC

Programming the pocket pc using the compact framework goes something like this.

(Dialog in my head)

1. "This feels like .NET I'll just write my usual .NET code"

2.  "Wait, there is no way to scroll a form the usual way I scroll in .NET"

3.  "Okay how do I get around this serious lack of functionality"

or

4.  "How can I get this done inside the Compact Framework which most of the time feels like .NET but isn't quite .NET"

Scrolling a form  is one of those snags that you need to google to figure out how to make it work since it doesn't behave like non-compact .NET.  The way to scroll in the compact framework is to:

1)  Insert a panel into the form
2)  Insert a vertical scroll bar control. 
3)  Place all controls you want to scroll in the panel
4) Trap the ValueChanged event of the scroll bar
5)  In the ValueChanged event handler, offset the top of the panel by the position of the scrollbar  (Listing 3)

Listing 3 - Vertical Scrollbar event handler that offsets the top of the panel containing the controls

private void vScrollBar1_ValueChanged(object sender, System.EventArgs e)
  {
    pnlPackingList.Top = - vScrollBar1.Value;
  }

 Other Snags

As I'm happily coding along,  I realized that I needed to find a way to abstract the list of packers from my Xml document.  It seems Microsoft left out XPath in the .NETCF 1.1 framework to keep the framework compact.   Good for memory storage....bad for the programmer (I long for the day that memory is not really an issue on the pocket pc...and at the rate technology is going, probably sometime in 2007).  In order to search nodes in the packing list, you need to use the GetElementsByTagName method in the XDocument class.  It doesn't quite give you the fine control over node searches as XPath, but it gives you a starting place for writing node search methods of your own.

Listing 4 - Grabbing the Packer Nodes out of the PackingList xml file

public ArrayList GetPackers()
 {
   ArrayList packers =
new ArrayList();
   XmlNodeList nodes = _xDoc.GetElementsByTagName("Packer");
  
foreach (XmlNode node in nodes)
    {
          packers.Add(node.Attributes["name"].Value); 
     }

  
return packers;
}

Conclusion

This application can use a bit of work,  but it is a good starting point for learning how to build forms on the pocket pc.  The scrolling functionality allows you to have an unlimited form length so you can play with adding additional controls to the program.  A few things that need to be added to make it more useable are (1) the ability to edit an existing item, (2) the ability to remove an item  (3) the ability to add your own category.  Another nice thing to have would be the ability to beam your packing list to your spouse, so they don't need to question you about forgetting any crucial travel material.  Anyway, there is a lot of information to pack into learning the compact framework.   Happy coding in the world of the C# and .NET on the pocket pc.


Similar Articles