Introduction
This application was written to aid a manager in the tracking of various unrelated projects. I wanted to store the projects in a XML file so that they could be imported into other software. There are two sections of code that may be interesting to people writing software in the .NET Compact Framework. These sections are the XML storage/retrieval and the IRDA support built into this application.
I am currently working on a PC version of this software that will allow me to update the projects file in my sync directory. After saving the information from one side or the other ActiveSync will update the opposite file in the My Documents directory. I can then re-load the file & be on my way. This is sort of a cheap way of using ActiveSync to keep both project managers updated. It would be nice to write the ActiveSync service providers, however it would take some time that I don't have right now.
Background
I have used Microsoft Project to track numerous projects within the same mpp file. Using Microsoft Project in this manner did not work very well. Microsoft Project seems to be great for building something like the space shuttle, but I needed a tool to allow me to track multiple projects for several engineers. Each engineer could be running two to three projects at a time, and we needed to keep track of the projects during the differing stages of their development. It is also useful to be able to take notes while speaking with the engineer working on the project and enter the notes into my Pocket PC. This lets me look up these notes while giving reports to my superiors and give the impression I really have control of my department.
Using the code
While attacking the problem of coding software to organize projects, I found that I needed several different classes. I created the following classes for logically organizing the projects.
Project - The main project contains a list of notes, information about the customer, a list of tasks, a list of todos, and many other small pieces of information like target date, sales order number, and engineering request number. There is a ProjectComparer
class that will sort the list of projects in ascending or descending order based upon the project name.
Note - A Note is a string with a DateTime
associated with it. The project has a list of these associated with it. There is a NoteComparer
class that will sort the notes in date order. This was created so that bottom most field on the main screen can have the description followed by all the notes in earliest to latest order.
Customer - The Customer class contains information about the customer, the company name, phone number and contact information.
Task - Tasks are chores to be done. They can be linked to other tasks, they may have durations and start dates. In the future this project manager could have the ability to have a Gantt chart associated with each project.
ToDo - This is similar to a task but only has a completed flag as well as a target date.
There is another class FileIO
, this is stored in the FileIO.cs file. There needed to be some code to save and restore files as well as transfer the files across the infra-red port. I wanted to keep this code out of the user interface so I created the FileIO
object. Saving the XML file is as easy as calling SaveFile()
. Similarly you can call the LoadFile()
routine to load a file, this is called during program startup, and upon the Re-Load menu click. The Loading code is as follows. I remove all of the projects, load the file, and re-sort the projects. The ReSort
routine will also invalidate the project list box so it is re-drawn.
myProjects.RemoveRange( 0, myProjects.Count );
(new FileIO()).LoadFile("\\My Documents\\Projects.xml", myProjects);
listOfProjectsReSort();
During the saving of a file I write out some of the data as attributes for the individual items in the project and elements with attributes in them for all the other lists in the projects.
fileWriter.WriteStartElement("Project");
fileWriter.WriteAttributeString("Name", p.Name );
fileWriter.WriteAttributeString("Description", p.Description );
fileWriter.WriteAttributeString("DueDate", p.DueDate );
fileWriter.WriteAttributeString("Manager", p.Resource );
...
fileWriter.WriteStartElement("Tasks");
foreach( task t in p.Tasks )
{
fileWriter.WriteStartElement("Task");
fileWriter.WriteAttributeString( "Name", t.Name);
fileWriter.WriteAttributeString( "Resource", t.Resource);
fileWriter.WriteAttributeString( "PrevTask", t.PrevTask);
fileWriter.WriteEndElement();
}
...
Parsing this information is pretty straightforward as well. I use a series of nested case statements to put the information in the appropriate fields. By setting up the code this way the XML file does not have to be in any order and any missing attributes are just ignored. You will notice that there is not very much error checking in this code & there is room for some improvement in terms of missing important information. For example I am not really sure what would happen if the name of the project is missing.
XmlDocument xmlDoc = new XmlDocument();
XmlTextReader reader = new XmlTextReader( fileToReadFrom);
try
{
xmlDoc.Load( reader );
XmlNode rootElement = xmlDoc.DocumentElement;
XmlNodeList xNodes = rootElement.ChildNodes;
foreach( XmlNode childNode in xNodes )
{
project pr = new project();
foreach( XmlAttribute attrib in childNode.Attributes )
{
switch ( attrib.Name )
{
case "Name" :
pr.Name = attrib.Value;
break;
case "Description" :
pr.Description = attrib.Value;
break;
...
}
}
foreach( XmlNode child in childNode.ChildNodes )
{
switch ( child.Name )
{
case "Customer" :
foreach( XmlAttribute attrib in child.Attributes )
{
switch ( attrib.Name )
{
case "Name" :
pr.Customer.Name = attrib.Value;
break;
case "Contact" :
pr.Customer.Contact = attrib.Value;
break;
...
CF Project Manager can also, via a popup menu, send a particular project across the infra-red port to another pocket PC. I wanted the ability to possibly send more than one (not possible in the current implementation) and during de-bugging to see what was going on. In order to accomplish these goals, I actually save a temporary XML file to the root directory with the projects to be sent in it. Then I use the SendFileToIR()
to send the file to a receiver. In my current implementation this file only has one project in it. You can also view this file utilizing the Notepad application built into the pocket PC.
foreach ( project p in myProjects )
{
if ( p.Name == listOfProjects.SelectedItem.ToString() )
{
ArrayList al = new ArrayList(1);
al.Add( p );
fio.SaveFile("\\tmpIRPrjs.txt", al);
break;
}
}
fio.SendFileToIR("\\tmpIRPrjs.txt");
At the startup of the program I start another thread with the receiver code in it. The receiver thread is started. The receiving thread is also in the FileIO
class. It is the SrvRoutine()
. This thread runs as long as the FileIO.isRunning
variable is set to true. This uses the IrDAListener
class to look at the Infra-red port to see watch for incoming files.
fio.isRunning = true;
this.thServ = new Thread (new ThreadStart(fio.SrvRoutine));
this.thServ.Start();
At shutdown you have to be sure to set the isRunning
variable to false to allow the thread to terminate. See the code below.
fio.isRunning = false;
Thread.Sleep(550);
Points of Interest
Comparers - There are some limitations to the Compact Framework's list boxes. These boxes are not sorted in any way. I had to utilize the Comparer classes to sort the lists each time the lists are modified to keep the listboxes sorted in alphabetical order. These Comparers are in the NoteComparer.cs file and the ProjectComparer.cs file.
I used some code from the Microsoft example IRSquirtCF. Here is a link to the example code. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/win_ce/htm/pwc_theirsquirtcfexample.asp
History
- Version 1.0 released for this article submission.