Home

XML-Based Applications:
College Park Auto-Parts

 

Introduction

After our various introductions to XML, we will put it to good use with a usable application. As a meta language, XML can be used to create text-based files that can be accessed by any application that reads XML. To highly support this language, the .NET Framework provides various classes that allow you to create very effective applications without investing a lot in client/server stuff.

In this lesson, we are going to create an application for a business that sells auto parts. The items sold in the store and the inventory are stored as XML files. When an employee is performing a customer order, we make the application friendly with lists that allow the user to select the necessary information using combo boxes. These include the year, the make and the model that allow to identify the specific car that a part is made for. After selecting the necessary parts, the employee can save the order. The order also is saved as an XML file.

All the orders of one particular day are saved to a common file. This allows the management to review the orders for a particular day. To review such orders, they can open another form that is equipped with a Date Picker and a DataGrid controls. The employee selects a date and the grid displays the list of items sold for that day, if any.

Prerequisites: To follow this lesson, you should be familiar with:

 

Practical Learning Practical Learning: Introducing the Application

  1. Start Microsoft Visual Studio .NET and create a Windows Application named CPAP3
  2. To add a new XML file, on the main menu, click File -> New -> File ...
  3. In the Templates list of the Add New Item dialog box, click XML File and click Open
  4. Complete the file as follows:
     
    <?xml version="1.0" encoding="utf-8" ?>
    <Cars>
    	<Make MakeName="Acura">
    		<Model>Integra GS 1.8L L4</Model>
    		<Model>MDX 3.5L V6</Model>
    		<Model>NSX 3.0L V6</Model>
    		<Model>NSX 3.2L V6</Model>
    		<Model>TL 3.2L V6</Model>
    	</Make>
    	<Make MakeName="Audi">
    		<Model>A4 Quattro 1.8L Turbo</Model>
    		<Model>A4 Quattro 3.0L V6</Model>
    		<Model>S4 2.7L V6</Model>
    	</Make>
    	<Make MakeName="BMW">
    		<Model>325I 2.5L L6</Model>
    		<Model>325XI 2.5L L6</Model>
    		<Model>745I 4.4L V8</Model>
    		<Model>Z3 Coupe 3.0L L6</Model>
    	</Make>
    </Cars>
  5. To save it, on the main menu, click File -> Save XMLFile1
  6. Locate the folder that contains the current project and display it in the Save In combo box
  7. Double-click its bin folder to  display it in the Save In combo box
  8. Double-click its debug folder to  display it in the Save In combo box
  9. Set the Name to Cars and click Save
  10. To add a new XML file, on the main menu, click File -> New -> File... In the Templates list of the Add New Item dialog box, click XML File and click Open
  11. Fill it up with a few parts as follows:
     
    <?xml version="1.0" encoding="utf-8" ?>
    <PartCategories>
    	<PartCategory>Accessories-Exterior</PartCategory>
    	<PartCategory>Belt Drive System</PartCategory>
    	<PartCategory>Body-Exterior</PartCategory>
    	<PartCategory>Body-Interior</PartCategory>
    	<PartCategory>Brake System</PartCategory>
    	<PartCategory>Clutch</PartCategory>
    	<PartCategory>Cooling System</PartCategory>
    	<PartCategory>Drivetrain</PartCategory>
    	<PartCategory>Electrical</PartCategory>
      	<PartCategory>Miscellaneous</PartCategory>
    </PartCategories>
  12. To save it, on the Standard toolbar, click the Save button
  13. Make sure the debug folder is displaying in the Save In combo box.
    Set the file name to PartCategories
  14. Add another XML file and fill it up with a few parts as follows:
     
    <?xml version="1.0" encoding="utf-8" ?>
    <Parts>
    	<Part>
    		<PartNumber>293749</PartNumber>
    		<CarYear>2005</CarYear>
    		<Make>Acura</Make>
    		<Model>NSX 3.0L V6</Model>
    		<PartName Category="Engine">Oil Filter</PartName>
    		<UnitPrice>8.85</UnitPrice>
    	</Part>
    	<Part>
    		<PartNumber>283759</PartNumber>
    		<CarYear>2002</CarYear>
    		<Make>Audi</Make>
    		<Model>A4 Quattro 1.8L Turbo</Model>
    		<PartName Category="Clutch">Clutch Release Bearing</PartName>
    		<UnitPrice>55.50</UnitPrice>
    	</Part>
    	<Part>
    		<PartNumber>368374</PartNumber>
    		<CarYear>2002</CarYear>
    		<Make>Audi</Make>
    		<Model>A4 Quattro 1.8L Turbo</Model>
    		<PartName Category="Electrical">Alternator</PartName>
    		<UnitPrice>305.50</UnitPrice>
    	</Part>
    	<Part>
    		<PartNumber>485704</PartNumber>
    		<CarYear>2002</CarYear>
    		<Make>Audi</Make>
    		<Model>A4 Quattro 1.8L Turbo</Model>
    		<PartName Category="Engine">Oil Filter</PartName>
    		<UnitPrice>5.50</UnitPrice>
    	</Part>
    	<Part>
    		<PartNumber>491759</PartNumber>
    		<CarYear>1998</CarYear>
    		<Make>BMW</Make>
    		<Model>325I 2.5L L6</Model>
    		<PartName Category="Ignition">Ignition Coil</PartName>
    		<UnitPrice>60.85</UnitPrice>
    	</Part>
    </Parts>
  15. Save it as Parts.xml in the debug folder

Application Design

To make our application intuitive, we will create a few objects as follows:

  1. New Make: This dialog box allows the user to create a new car make that will eventually be used to identify a part
  2. New Model: This dialog box is used to create a new car model
  3. New Part Category: In order to restrict the search of a part, the items of this store will be categorized. This dialog box is used to create the categories of items
  4. New Part: This is the main form used to create each part or item sold in the store. To create an item, the user must specify the year of the car, its model, and the type or category of the item. Then the user must create a name for the part; this can also be a short description. The user must also specify the price of the item. For inventory purposes, each item sold in the store must have a number. To make this easy, we will write our own code to automatically generate a number but the user can still change it.
    Once the item is ready, the user can click the Add Part button. This creates the item and stores it in the XML file used for general inventory
  5. Order Processing: This is the form used to select a part or an item requested by a customer

When designing this type of application, you should keep in mind to make it as user friendly as possible, which is what we did. Still, you are free to change our design to what suits you.

 

Practical Learning Practical Learning: Designing the Application

  1. To add a new form, on the main menu, click Project -> Add Windows Form...
  2. In the Templates list of the Add New Item dialog box, make sure Windows Forms is selected.
    Set the Name to NewMake and press Enter
  3. Design the form as follows:
     
    College Park Auto-Parts: New Make Form - Form Design
    Control Name Text Other Properties
    Label   New Car Make:  
    TextBox txtNewMake   Modifiers: Public
    Button btnOK OK DialogResult: OK
    Button btnCancel Cancel DialogResult: Cancel
    Form     AcceptButton: btnOK
    CancelButton: btnCancel
    FormBorderStyle: FixedDialog
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskbar: False
    StartPosition: CenterScreen
  4. To add a new form, on the main menu, click Project . Add Windows Form...
  5. Set the Name to NewModel and press Enter
  6. Design the form as follows:
     
    College Park Auto-Parts: New Car Model - Form Design
    Control Name Text Other Properties
    Label   Make:  
    ComboBox cboMakes   DropDownStyle: DropDownList
    Button btnNewMake New Make  
    Label   Model:  
    TextBox txtNewModel    
    Button btnOK OK DialogResult: OK
    Button btnCancel Cancel DialogResult: Cancel
    Form     AcceptButton: btnOK
    CancelButton: btnCancel
    FormBorderStyle: FixedDialog
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskbar: False
    StartPosition: CenterScreen
  7. Double-click the New Make button and implement its Click event as follows:
     
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Xml;
    
    namespace CPAP3a
    {
    		 
    			. . . No Change
    	
    
    		private void btnNewMake_Click(object sender, System.EventArgs e)
    		{
    			NewMake frmNewMake = new NewMake();
    
    			frmNewMake.ShowDialog();
    		}
    	}
    }
  8. To add a new form, on the main menu, click Project -> Add Windows Form
  9. Set the Name to NewPartCategory and press Enter
  10. Design the form as follows:
     
    Collge Park Auto-Parts: New Part Category - Form Design
    Control Name Text Other Properties
    Label   New Category:  
    TextBox txtNewCategory   Modifiers: Public
    Button btnOK OK DialogResult: OK
    Button btnCancel Cancel DialogResult: Cancel
    Form   New Make AcceptButton: btnOK
    CancelButton: btnCancel
    FormBorderStyle: FixedDialog
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskbar: False
    StartPosition: CenterScreen
  11. To add a new form, on the main menu, click Project -> Windows Forms
  12. Set the Name to NewPart and press Enter
  13. Design the form as follows:
     
    New Part
    Control Name Text Other Properties
    Label   Year:  
    ComboBox cboYears   DropDownStyle: DropDownList
    Modifiers: Public
    Label   Make:  
    ComboBox cboMakes   DropDownStyle: DropDownList
    Modifiers: Public
    Button btnNewMake New Make  
    Label   Model:  
    ComboBox cboModels   DropDownStyle: DropDownList
    Modifiers: Public
    Button btnNewModel New Model  
    Label   Part Category:  
    ComboBox cboPartCategories   DropDownStyle: DropDownList
    Modifiers: Public
    Button btnNewCategory New Category  
    Label   Part Name:  
    TextBox txtPartName   Modifiers: Public
    Label   Unit Price:  
    TextBox txtUnitPrice 0.00 Modifiers: Public
    TextAlign: Right
    Label   Part #:  
    TextBox txtPartNumber 000000 Modifiers: Public
    TextAlign: Right
    Button btnAddPart Add Part  
    Button btnClose Close  
    Form     AcceptButton: btnAdd
    CancelButton: btnClose
    MaximizeBox: False
    StartPosition: CenterScreen
  14. Double-click an unoccupied area of the form to access its Load event and implement its as follows:
     
    private void NewPart_Load(object sender, System.EventArgs e)
    {
    	// Fill the Year combo box with years from 1960 to the coming year
    	for(int i = DateTime.Now.Year+1; i >= 1960; i--)
    		this.cboYears.Items.Add(i.ToString());
    
    	// We will generate a random number for the item
    	// To start, we will use the miliseconds as a seed
    	DateTime tmeNow = DateTime.Now;
    	int ms = tmeNow.Millisecond;
    
    	// Now we can generate a random number between 100000 and 999999
    	Random rndNumber = new Random(ms);
    
    	// Generate three randomg characters
    	Char firstCharacter  = (Char)(rndNumber.Next(65, 90));
    		Char secondCharacter = (Char)(rndNumber.Next(65, 90));
    	Char thirdCharacter  = (Char)(rndNumber.Next(65, 90));
    	// Generate a random number made of 4 digits
    	int numberPart = rndNumber.Next(1000, 9999);
    	 
    	// Exclude the digits 1 and 0 because they create confusion
    	if( firstCharacter == 'I' || firstCharacter == 'O' )
    		firstCharacter = 'A';
    	if( secondCharacter == 'I' || secondCharacter == 'O' )
    		secondCharacter = 'A';
    	if( thirdCharacter == 'I' || thirdCharacter == 'O' )
    		thirdCharacter = 'A';
    	// Generate a random number between 1 and 3
    	int rndCombination = rndNumber.Next(1, 4);
    	string strPartNumber = null;
    
    	// Create a part number using some algorithm
    	if( rndCombination == 1 )
    	strPartNumber = firstCharacter.ToString() + secondCharacter.ToString() +
    			numberPart.ToString() + thirdCharacter.ToString());
    	else if( rndCombination == 2 )
    		strPartNumber = firstCharacter.ToString() + numberPart.ToString() +
    			secondCharacter.ToString() + thirdCharacter.ToString());
    	else if( rndCombination == 3 )
    		strPartNumber = numberPart.ToString() + firstCharacter.ToString() +
    			secondCharacter.ToString() + thirdCharacter.ToString());
    	else
    		strPartNumber = rndNumber.Next(100000, 999999).ToString();
    
    	// Display the new number in the Part # text box
    	this.txtPartNumber.Text = strPartNumber;
    
    	// Disable the OK button to indicate that the part is not ready
    	this.btnAddPart.Enabled = false;
    }
  15. Return to the New Part form and double-click the New Make button
  16. Return to the New Part form and double-click the New Model button
  17. Return to the New Part form and double-click the New Category button
  18. Return to the New Part form and double-click the Close button
  19. Implement the Click events as follows:
     
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Xml;
    
    namespace CPAP3a
    {
    	
    	. . . No Change
    		
    		
    private void btnNewMake_Click(object sender, System.EventArgs e)
    {
    	NewMake frmNewMake = new NewMake();
    
    	frmNewMake.ShowDialog();
    }
    
    private void btnNewModel_Click(object sender, System.EventArgs e)
    {
    	NewModel frmNewModel = new NewModel();
    
    	 frmNewModel.ShowDialog();
    }
    
    private void btnNewCategory_Click(object sender, System.EventArgs e)
    {
    	NewPartCategory frmCat = new NewPartCategory();
    
    	 frmCat.ShowDialog();
    }
    
    private void btnClose_Click(object sender, System.EventArgs e)
    {
    	Close();
    }
    }
    }		
  20. To add a new form, on the main menu, click Project -> Windows Forms
  21. Set the Name to OrderProcessing and press Enter
  22. Design the form as follows:
     
    College Park Auto Parts - Order Processing - Form Design
    Control Name Text Other Properties
    GroupBox   Part Selection  
    Label   Year:  
    Label      
    ComboBox cboYears   DropDownStyle: DropDownList
    Label   Make:  
    ComboBox cboModels   DropDownStyle: DropDownList
    Label   Model:  
    ComboBox cboMakes   DropDownStyle: DropDownList
    Label   Category:  
    ComboBox cboCategories   DropDownStyle: DropDownList
    Label   Available Parts  
    ListView lvwAvailableParts   FullRowSelect: True
    GridLines: True
    Columns:
    Text TextAlign Width
    Part # Center 60
    Part Name Left 220
    Unit Price Right 60
    GroupBox   Setup  
    Button btnNewPart New Part  
    Button btnClose Close  
    GroupBox   Customer Order  
    Label   Part #  
    Label   Part Name  
    Label   Unit Price  
    Label   Qty  
    Label   Sub Total  
    Label   Keep Remove  
    TextBox txtPartNumber1    
    TextBox txtPartName1    
    TextBox txtUnitPrice1 0.00 TextAlign: Right
    TextBox txtQuantity1 0 TextAlign: Right
    TextBox txtSubTotal1 0.00 TextAlign: Right
    CheckBox chkKeepRemove1    
    TextBox txtPartNumber2    
    TextBox txtPartName2    
    TextBox txtUnitPrice2 0.00 TextAlign: Right
    TextBox txtQuantity2 0 TextAlign: Right
    TextBox txtSubTotal2 0.00 TextAlign: Right
    CheckBox chkKeepRemove2    
    TextBox txtPartNumber3    
    TextBox txtPartName3    
    TextBox txtUnitPrice3 0.00 TextAlign: Right
    TextBox txtQuantity3 0 TextAlign: Right
    TextBox txtSubTotal3 0.00 TextAlign: Right
    CheckBox chkKeepRemove3    
    TextBox txtPartNumber4    
    TextBox txtPartName4    
    TextBox txtUnitPrice4 0.00 TextAlign: Right
    TextBox txtQuantity4 0 TextAlign: Right
    TextBox txtSubTotal4 0.00 TextAlign: Right
    CheckBox chkKeepRemove4    
    TextBox txtPartNumber5    
    TextBox txtPartName5    
    TextBox txtUnitPrice5 0.00 TextAlign: Right
    TextBox txtQuantity5 0 TextAlign: Right
    TextBox txtSubTotal5 0.00 TextAlign: Right
    CheckBox chkKeepRemove5    
    TextBox txtPartNumber6    
    TextBox txtPartName6    
    TextBox txtUnitPrice6 0.00 TextAlign: Right
    TextBox txtQuantity6 0 TextAlign: Right
    TextBox txtSubTotal6 0.00 TextAlign: Right
    CheckBox chkKeepRemove6    
    Label   Order saved in  
    DateTimePicker dtpFilename   Format: Custom
    CustomFormat: ddMMMyyyy
    Button btnSave Save  
    Label   Total Order:  
    TextBox txtTotalOrder 0.00 TextAlign: Right
  23. Double an unoccupied area of the form outside of any group box to generate the form's Load event
  24. Implement the Load event as follows:
     
    private void OrderProcessing_Load(object sender, System.EventArgs e)
    {
    // Fill the Year combo box with years from 1960 to the coming year
    	for(int i = DateTime.Now.Year+1; i >= 1960; i--)
    		this.cboYears.Items.Add(i.ToString());
    }
  25. In the top section of the file, under the other using lines, type:
     
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.IO;
    using System.Xml;
  26. Return to the form and double-click the New Part button
  27. Implement its Click event as follows:
     
    private void btnNewPart_Click(object sender, System.EventArgs e)
    {
    	NewPart frmPart = new NewPart();
    
    	frmPart.ShowDialog();
    }
  28. Return to the form. Double-click the Close button and implement its Click event as follows:
     
    private void btnClose_Click(object sender, System.EventArgs e)
    {
    	Close();
    }
  29. Display the first or main form (Form1.cs [Design]) and design it as follows 
     
    Collge Park Auto-Parts: Switchboard Form Design
    Control Name Text
    Button btnOrderProcessing Order Processing
    Button btnNewPart New Part
    Button btnClose Close
  30. Double-click the Order Processing button
  31. Return to the form and double-click the New Part button
  32. Return to the form and double-click the Close button
  33. Implement the Click events as follows:
     
    private void btnOrderProcessing_Click(object sender, System.EventArgs e)
    {
    	OrderProcessing frmOrder = new OrderProcessing();
    
    	frmOrder.ShowDialog();
    }
    
    private void btnNewPart_Click(object sender, System.EventArgs e)
    {
    	NewPart frmPart = new NewPart();
    
    	frmPart.ShowDialog();
    }
    
    private void btnClose_Click(object sender, System.EventArgs e)
    {
    	Close();
    }
  34. Execute the application to test it
 

Using the Document Object Model (DOM)

The main purpose of this application is to take advantage of XML and the Document Object Model (DOM) as it is implemented in the .NET Framework through the XmlDocument class. As mentioned in our lessons on XML, the XmlDocument class provides the necessary methods to create an element, to locate one, and to managed. To perform some of these operations, it gets assisted by the XmlNode and its derived classes. Based on this, we will use those classes to create parts and items sold in the store.

Before creating a part, the application must have a list of cars. To start, we created a sample XML file that contained a few cars. Here, we will all the user to add new model and add them to the file. We will create new models from the New Model dialog box.

When designing the New Part form, we equipped it with a few combo boxes. When the New Part form displays, we will make sure that those combo boxes are filled with the information that is already stored in the corresponding XML files. 

 

Practical Learning Practical Learning: Introducing the Document Object Model (DOM)

  1. Display the New Model form and double-click an unoccupied area of the form to access its Load event
  2. Implement the Load event as follows:
     
    private void NewModel_Load(object sender, System.EventArgs e)
    {
    	// We will need a reference to the XML document
    	XmlDocument docXML = new XmlDocument();
    
    	// We will start with the Make combo box
    	// Open the Cars.xml file
    	docXML.Load("Cars.xml");
    	// Get a reference to the root node
    	XmlElement nodRoot = docXML.DocumentElement;
    	// Locate all nodes whose name is Make
    	XmlNodeList nodItems = nodRoot.GetElementsByTagName("Make");
    	// Retrieve the value of each Make node and put 
    	// that value in the Make combo box
    	for(int i = 0; i < nodItems.Count; i++)
    		this.cboMakes.Items.Add(nodItems[i].Attributes["MakeName"].InnerText);
    }
  3. Access the New Part form and change its Load event as follows:
     
    private void NewPart_Load(object sender, System.EventArgs e)
    {
    	// Fill the Year combo box with years from 1960 to the coming year
    	for(int i = DateTime.Now.Year+1; i >= 1960; i--)
    		this.cboYears.Items.Add(i.ToString());
    
    	// We will need a reference to the XML document
    	XmlDocument docXML = new XmlDocument();
    
    	// Open the Cars.xml file
    	docXML.Load("Cars.xml");
    
    	// Get a reference to the root node
    	XmlElement nodRoot = docXML.DocumentElement;
    	// Locate all nodes whose name is Make
    	XmlNodeList nodItems = nodRoot.GetElementsByTagName("Make");
    	// Retrieve the value of each Make node and put 
    	// that value in the Make combo box
    	for(int i = 0; i < nodItems.Count; i++)
    		this.cboMakes.Items.Add(nodItems[i].Attributes["MakeName"].InnerText);
    
    	// Open the Makes.xml file
    	docXML.Load("PartCategories.xml");
    
    	// Get a reference to the root node
    	nodRoot = docXML.DocumentElement;
    	// Locate all nodes whose name is Make
    	nodItems = nodRoot.GetElementsByTagName("PartCategory");
    	// Retrieve the value of each Make node and put 
    	// that value in the Make combo box
    	for(int i = 0; i < nodItems.Count; i++)
    		this.cboPartCategories.Items.Add(nodItems[i].InnerText);
    
    	this.cboPartCategories.Text = "Miscellaneous";
    
    	// We will generate a random number for the item
    	// To start, we will use the miliseconds as a seed
    	DateTime tmeNow = DateTime.Now;
    	int ms = tmeNow.Millisecond;
    
    	// Now we can generate a random number between 100000 and 999999
    	Random rndNumber = new Random(ms);
    
    	// Generate three randomg characters
    	Char firstCharacter  = (Char)(rndNumber.Next(65, 90));
    	Char secondCharacter = (Char)(rndNumber.Next(65, 90));
    	Char thirdCharacter  = (Char)(rndNumber.Next(65, 90));
    	// Generate a random number made of 4 digits
    	int numberPart = rndNumber.Next(1000, 9999);
    	 
    	// Exclude the digits 1 and 0 because they create confusion
    	if( firstCharacter == 'I' || firstCharacter == 'O' )
    		firstCharacter = 'A';
    	if( secondCharacter == 'I' || secondCharacter == 'O' )
    		secondCharacter = 'A';
    	if( thirdCharacter == 'I' || thirdCharacter == 'O' )
    		thirdCharacter = 'A';
    	// Generate a random number between 1 and 3
    	int rndCombination = rndNumber.Next(1, 4);
    	string strPartNumber = null;
    
    	// Create a part number using some algorithm
    	if( rndCombination == 1 )
    		strPartNumber = firstCharacter.ToString() + secondCharacter.ToString() +
    			numberPart.ToString() + thirdCharacter.ToString();
    	else if( rndCombination == 2 )
    		strPartNumber = firstCharacter.ToString() + numberPart.ToString() +
    			secondCharacter.ToString() + thirdCharacter.ToString();
    	else if( rndCombination == 3 )
    		strPartNumber = numberPart.ToString() + firstCharacter.ToString() +
    			secondCharacter.ToString() + thirdCharacter.ToString();
    	else
    		strPartNumber = rndNumber.Next(100000, 999999).ToString();
    
    	// Display the new number in the Part # text box
    	this.txtPartNumber.Text = strPartNumber;
    
    	// Disable the OK button to indicate that the part is not ready
    	this.btnAddPart.Enabled = false;
    }
  4. Access the Cars.xml file. To add a comment, change it as follows:
     
    <?xml version="1.0" encoding="utf-8" ?> 
    <Cars>
    	<!-- Each car model is organized as follows:
    	       1. The first part identifies the make of the car.
    	           We use a MakeName attribute of the Make element
    	           to identify a make
    	       2. The second part identifies the name of the model.
    	-->
    	<Make MakeName="Acura">
    		<Model>Integra GS 1.8L L4</Model>
    		<Model>MDX 3.5L V6</Model>
    		<Model>NSX 3.0L V6</Model>
    		<Model>NSX 3.2L V6</Model>
    		<Model>TL 3.2L V6</Model>
    	</Make>
    	<Make MakeName="Audi">
    		<Model>A4 Quattro 1.8L Turbo</Model>
    		<Model>A4 Quattro 3.0L V6</Model>
    		<Model>S4 2.7L V6</Model>
    	</Make>
    	<Make MakeName="BMW">
    		<Model>325I 2.5L L6</Model>
    		<Model>325XI 2.5L L6</Model>
    		<Model>745I 4.4L V8</Model>
    		<Model>Z3 Coupe 3.0L L6</Model>
    	</Make>
    </Cars>
  5. Save the file
  6. Execute the application to test it and make sure that the top combo boxes of the New Part and the New Model forms are rightly filled
  7. Close the form and return to your programming environment

Inventory Creation

The inventory of our store is created by adding items to an XML file. To do this, once again, we take advantage of the XmlDocument, the XmlNode, and its derived classes. This inventory is done using the New Part form.

We need to apply some rules in order to create an item. Early rules can make the application easier to use and maintain. For example, we must create an item only if it can be clearly identified. This makes it easy to locate it when processing an order. We explain through the comments in the code.

 

Practical Learning Practical Learning: Creating the Inventory

  1. Display the New Model form and double-click the New Make button
  2. Change the Click event of the btnNewMake button as follows:
     
    private void btnNewMake_Click(object sender, System.EventArgs e)
    {
    	// The new car make will come from the New Make dialog box
    	 NewMake frmMake = new NewMake();
    
    	 // Display the New Make dialog box and find out if the user clicked OK
    	 if( frmMake.ShowDialog() == DialogResult.OK )
    	 {
    		 string strNewMake = frmMake.txtNewMake.Text;
    
    		 // If the user didn't create a new Make, don't do anything
    		 if( strNewMake == "" )
    			 return;
    
    		 // Before adding the new make, check that it doesn't exist already
    		 if( this.cboMakes.FindStringExact(strNewMake) > 0 )
    			 return;
    
    		 // Now you can add it
    		 this.cboMakes.Items.Add(strNewMake);
    		 // The user likely wants this new item selected
    		 this.cboMakes.Text = strNewMake;
    
    		 // Open the Cars.xml file
    		 XmlDocument docXMLFile = new XmlDocument();
    		 docXMLFile.Load("Cars.xml");
    
    		 // Get the root node so we can explore its children
    		 XmlNode nodRoot = docXMLFile.DocumentElement;
    		 
    		 // If the car is not in the list already, create its Make node
    		 XmlNode nodNewMake  = docXMLFile.CreateNode(XmlNodeType.Element, "Make", "");
    		 // Create an attribute for the node
    		 ((XmlElement)(nodNewMake)).SetAttribute("MakeName", strNewMake);
    		 
    		 // Add the new node to the XML file
    		 docXMLFile.DocumentElement.AppendChild(nodNewMake);
    		 
    		 // Save the file
    		 docXMLFile.Save("Cars.xml");
    	}
    }
  3. Display the New Part form and double-click the New Make button
  4. Change the Click event of the btnNewMake button as follows:
     
    private void btnNewMake_Click(object sender, System.EventArgs e)
    {
    	// The new car make will come from the New Make dialog box
    	 NewMake frmMake = new NewMake();
    
    	 // Display the New Make dialog box and find out if the user clicked OK
    	 if( frmMake.ShowDialog() == DialogResult.OK )
    	 {
    		 string strNewMake = frmMake.txtNewMake.Text;
    
    		 // If the user didn't create a new Make, don't do anything
    		 if( strNewMake == "" )
    			 return;
    
    		 // Before adding the new make, check that it doesn't exist already
    		 if( this.cboMakes.FindStringExact(strNewMake) > 0 )
    			 return;
    
    		 // Now you can add it
    		 this.cboMakes.Items.Add(strNewMake);
    		 // The user likely wants this new item selected
    		 this.cboMakes.Text = strNewMake;
    
    		 // Open the Cars.xml file
    		 XmlDocument docXMLFile = new XmlDocument();
    		 docXMLFile.Load("Cars.xml");
    
    		 // Get the root node so we can explore its children
    		 XmlNode nodRoot = docXMLFile.DocumentElement;
    		 
    		 // If the car is not in the list already, create its Make node
    		 XmlNode nodNewMake  = docXMLFile.CreateNode(XmlNodeType.Element, "Make", "");
    		 // Create an attribute for the node
    		 ((XmlElement)(nodNewMake)).SetAttribute("MakeName", strNewMake);
    		 
    		 // Add the new node to the XML file
    		 docXMLFile.DocumentElement.AppendChild(nodNewMake);
    		 
    		 // Save the file
    		 docXMLFile.Save("Cars.xml");
    	}
    }
  5. Display the New Part form again and double-click the New Model button
  6. Change its Click event as follows:
     
    private void btnNewModel_Click(object sender, System.EventArgs e)
    {
    	// The new car model will come from the New Model dialog box
    	 NewModel frmModel = new NewModel();
    
    	 // Display the New Model dialog box and find out if the user clicked OK
    	 if( frmModel.ShowDialog() == DialogResult.OK )
    	 {
    		 // Retrieve the values that the user specified
    		 string strMake     = frmModel.cboMakes.Text;
    		 string strNewModel = frmModel.txtNewModel.Text;
    
    		 // If the new didn't select a Make, don't do anything
    		 if( strMake.Equals("") )
    			 return;
    		 // If the New Model string is empty, don't do anything
    		 if( strNewModel.Equals("") )
    			 return;
    
    		 // Open the Cars.xml file
    		 XmlDocument docXMLFile = new XmlDocument();
    		 docXMLFile.Load("Cars.xml");
    
    		 // Get the root node so we can explore its children
    		 XmlNode nodRoot = docXMLFile.DocumentElement;
    		 
    		 // Create a list of all Make nodes
    		 XmlNodeList lstMakes = docXMLFile.GetElementsByTagName("Make");
    
    		 // Visit each Make
    		 for(int i = 0; i < lstMakes.Count; i++)
    		 {
    			 // Get a reference to the current node
    			 XmlNode curMake = lstMakes[i];
    
    			 // If, or when you find the Make
    			 if( curMake.Attributes["MakeName"].InnerText.Equals(strMake) )
    			 {
    				 // Since we found the Make, find out if the model exists
    				 XmlNodeList lstCurrentModels = curMake.ChildNodes;
    
    				 // Check each model if the list already contains the model
    				 for(int j = 0; j < lstCurrentModels.Count; j++)
    				 {
    				if( lstCurrentModels[j].InnerText.Equals(strNewModel) )
    					 {
    			MessageBox.Show("That model exists already in the database");
    						 return;
    					 }
    				 }
    
    				 // create a child node to it
    	    XmlNode nodModel = docXMLFile.CreateNode(XmlNodeType.Element, "Model", "");
    			 // Create its value using the string from the New Make dialog box
    				 nodModel.InnerText = strNewModel;
    				 // Add the new element at the end of the file
    				 curMake.AppendChild(nodModel);
    
    				 // Save the file
    				 docXMLFile.Save("Cars.xml");
    				 break;
    			 }
    		 }
    	}
    }
  7. Display the New Part form again and double-click the Make combo box
  8. Implement its SelectedIndexChanged event as follows:
     
    private void cboMakes_SelectedIndexChanged(object sender, System.EventArgs e)
    {
    	// Empty the Models combo box
    	this.cboModels.Items.Clear();
    
    	// Find out if the user had selected a Make
    	string strSelectedMake = this.cboMakes.Text;
    	// Open the Cars.xml file
    	XmlDocument docXML = new XmlDocument();
    	docXML.Load("Cars.xml");
    
    	// Get a reference to the root node
    	XmlElement nodRoot = docXML.DocumentElement;
    	// Locate all nodes whose name is Make
    	XmlNodeList nodMakes = nodRoot.GetElementsByTagName("Make");
    	// Look for the Make that is the same the user selected
    	for(int i = 0; i < nodMakes.Count; i++)
    	{
    		// Retrieve the value of each Make node and put
    	string strMakeName = nodMakes[i].Attributes["MakeName"].InnerText;
    		// If you find it...
    		if( strMakeName.Equals(strSelectedMake) )
    		{
    			// If you find it, make a list of its models...
    		XmlNodeList nodAvailableModels = nodMakes[i].ChildNodes;
    		// ... then add each of its models to the Model combo box
    			for(int j = 0; j < nodAvailableModels.Count; j++)
    		this.cboModels.Items.Add(nodAvailableModels[j].InnerText);
    		}
    	}
    }
  9. Display the New Part form again and double-click the New Category button
  10. Change its Click event as follows:
     
    private void btnNewCategory_Click(object sender, System.EventArgs e)
    {
    	// Get a reference to the New Part Category form
    	 NewPartCategory frmCategory = new NewPartCategory();
    
    	 // Display the New Part Category dialog box and find out if the user clicked OK
    	 if( frmCategory.ShowDialog() == DialogResult.OK )
    	 {
    		 string strCategory = frmCategory.txtNewCategory.Text;
    
    		 // If the user didn't create a new category, don't do anything
    		 if( strCategory.Equals("") )
    			 return;
    
    		 // Before adding the new category, check that it doesn't exist already
    		 if( this.cboPartCategories.FindStringExact(strCategory) > 0 )
    			 return;
    
    		 // Now you can add it
    		 this.cboPartCategories.Items.Add(strCategory);
    		 // The user likely wants this new item selected
    		 this.cboPartCategories.Text = strCategory;
    
    		 // Open the PartCategories.xml file
    		 XmlDocument docXMLFile = new XmlDocument();
    		 docXMLFile.Load("PartCategories.xml");
    
    		 // Get the root node so we can explore its children
    		 XmlNode nodRoot = docXMLFile.DocumentElement;
    		 
    		 // If the new part is not in the list already, create its node
    XmlNode nodNewCategory  = docXMLFile.CreateNode(XmlNodeType.Element, "PartCategory", "");
    		 // Create text for the node
    		 nodNewCategory.InnerText = strCategory;
    		 
    		 // Add the new node to the XML file
    		 docXMLFile.DocumentElement.AppendChild(nodNewCategory);
    		 
    		 // Save the file
    		 docXMLFile.Save("PartCategories.xml");
    	}
    }
  11. Return to the New Part form and double-click the Part Name text box
  12. Implement its TextChanged event as follows:
     
    private void txtPartName_TextChanged(object sender, System.EventArgs e)
    {
    	// If there is no part name, no need to add the item to the XML file
    	if( this.txtPartName.Text == "" )
    		this.btnAddPart.Enabled = false;
    	else
    		this.btnAddPart.Enabled = true;
    }
  13. Return to the New Part form and double-click the Unit Price text box
  14. Implement its TextChanged event as follows:
     
    private void txtUnitPrice_TextChanged(object sender, System.EventArgs e)
    {
    	// If the price is not specified, don't add the item to the XML file
    	if( this.txtUnitPrice.Text == "" )
    		this.btnAddPart.Enabled = false;
    	else
    		this.btnAddPart.Enabled = true;
    }
  15. Return to the New Part form and double-click the Part # text box
  16. Implement its TextChanged event as follows:
     
    private void txtPartNumber_TextChanged(object sender, System.EventArgs e)
    {
    	// Make sure that there is a Part Number for this item
    	// Otherwise, don't add the part to the XML file
    	if( this.txtPartNumber.Text == "" )
    		this.btnAddPart.Enabled = false;
    	else
    		this.btnAddPart.Enabled = true;
    }
  17. Return to the New Part form and double-click the Add Part button
  18. Implement its Click event as follows:
     
    private void btnAddPart_Click(object sender, System.EventArgs e)
    {
    	// Open the Parts.xml file
    	XmlDocument docXML = new XmlDocument();
    	docXML.Load("Parts.xml");
    
    	// Before adding the new part, make sure all components are ready
    	// Otherwise, don't add it
    	if( this.cboYears.SelectedIndex < 0 )
    	{
    		MessageBox.Show("You must specify the year. " +
    			"This will help to locate the part");
    		this.cboYears.Focus();
    		return;
    	}
    	if( this.cboMakes.SelectedIndex < 0 )
    	{
    		MessageBox.Show("Please select the car make for this part.");
    		this.cboMakes.Focus();
    		return;
    	}
    	if( this.cboModels.SelectedIndex < 0 )
    	{
    		MessageBox.Show("The car model is required. " +
    			"It helps to know the specific car this part is made for.");
    		this.cboModels.Focus();
    		return;
    	}
    	if( this.txtPartName.Text.Equals("") )
    	{
    	MessageBox.Show("You must specify the part name or a (very) short description.");
    		this.txtPartName.Focus();
    		return;
    	}
    	if( this.txtUnitPrice.Text.Equals("") )
    	{
    		MessageBox.Show("You must enter the price of each unit of this part.");
    		this.txtUnitPrice.Focus();
    		return;
    	}
    	if( this.txtPartNumber.Text.Equals("") )
    	{
    		MessageBox.Show("Every item of this database must have a number. " +
    			"The number is just a combination of letters and digits." +
    			"Please make up a number and enter it in the Part # box.");
    		this.txtPartNumber.Focus();
    		return;
    	}
    
    	// The part seems to be ready
    	// Get a reference to the root node
    	XmlElement nodNewPart = docXML.CreateElement("Part");
    	// Create a new part as a child of the root (this is a simple node addition
    	string strNewPart = "<PartNumber>", this.txtPartNumber.Text, "</PartNumber>" +
    				"<CarYear>", this.cboYears.Text, "</CarYear>" +
    				"<Make>", this.cboMakes.Text, "</Make>" +
    				"<Model>", this.cboModels.Text, "</Model>" +
    				"<PartName Category=\"", this.cboPartCategories.Text,"\">" +
    				this.txtPartName.Text, "</PartName>" +
    				"<UnitPrice>", this.txtUnitPrice.Text, "</UnitPrice>");
    	nodNewPart.InnerXml = strNewPart;
    	docXML.DocumentElement.AppendChild(nodNewPart);
    	docXML.Save("Parts.xml");
    
    	// Reset the form in case the user wants to add another part
    	this.cboYears.SelectedIndex = -1;
    	this.cboMakes.SelectedIndex = -1;
    	this.cboModels.SelectedIndex = -1;
    	this.cboPartCategories.Text = "Miscellaneou";
    	this.txtPartName.Text = "";
    	this.txtUnitPrice.Text = "";
    	 
    	// We will generate a random number for the item
    	// To start, we will use the miliseconds as a seed
    	DateTime tmeNow = DateTime.Now;
    	int ms = tmeNow.Millisecond;
    
    	// Now we can generate a random number between 100000 and 999999
    	Random rndNumber = new Random(ms);
    
    	// Generate three randomg characters
    	Char firstCharacter  = (Char)(rndNumber.Next(65, 90));
    	Char secondCharacter = (Char)(rndNumber.Next(65, 90));
    	Char thirdCharacter  = (Char)(rndNumber.Next(65, 90));
    	// Generate a random number made of 4 digits
    	int numberPart = rndNumber.Next(1000, 9999);
    	 
    	// Exclude the digits 1 and 0 because they create confusion
    	if( firstCharacter == 'I' || firstCharacter == 'O' )
    		firstCharacter = 'A';
    	if( secondCharacter == 'I' || secondCharacter == 'O' )
    		secondCharacter = 'A';
    	if( thirdCharacter == 'I' || thirdCharacter == 'O' )
    		thirdCharacter = 'A';
    	// Generate a random number between 1 and 3
    	int rndCombination = rndNumber.Next(1, 4);
    	string strPartNumber = null;
    
    	// Create a part number using some algorithm
    	if( rndCombination == 1 )
    		strPartNumber = firstCharacter.ToString() + secondCharacter.ToString() +
    			numberPart.ToString() + thirdCharacter.ToString();
    	else if( rndCombination == 2 )
    		strPartNumber = firstCharacter.ToString() + numberPart.ToString() + 
    			secondCharacter.ToString() + thirdCharacter.ToString();
    	else if( rndCombination == 3 )
    		strPartNumber = numberPart.ToString() + firstCharacter.ToString() +
    			secondCharacter.ToString() + thirdCharacter.ToString();
    	else
    		strPartNumber = rndNumber.Next(100000, 999999).ToString();
    
    	// Display the new number in the Part # text box
    	this.txtPartNumber.Text = strPartNumber;
    	this.cboYears.Focus();
    }
  19. Execute the application to test it
  20. Add a few parts as follows (let the computer generate part numbers):
     
    Year Make Model Part Category Part Name Unit Price
    2002 Audi A4 Quattro 1.8L Turbo Exhaust Exhaust Gasket 1.55
    2004 Dodge Neon SE 2.0L L4 Cooling System Radiator Fan Assembly 125.95
    2002 Audi A4 Quattro 1.8L Turbo Drivetrain Axle Differential Bearing - Left 10.25
    2000 Ford Escort 2.0L L4 Ignition Crankshaft Position Sensor 18.65
    2002 Chevrolet Silverado 2500 5.3L V8 Ignition Spark Plugs 1.55
    2004 Dodge Neon SE 2.0L L4 Engine Oil Pump 112.85
    2004 Dodge Neon SE 2.0L L4 Engine Exhaust Valve 5.85
    1986 Acura Integra LS 1.8L L4 Electrical Alternator 110.75
    1998 Toyota Corolla 1.8L L4 Cooling System Radiator 95.95
    2002 Dodge Dakota 3.9L V6 Electrical Starter Motor 145.95
    2004 Honda Civic EX 1.7L L4 Emission Oxygen Sensor 90.55
    2002 Audi A4 Quattro 1.8L Turbo Electrical Alternator 305.50
    2002 Acura NSX 3.0L V6 Engine Oil Filter 7.05
    1998 Jeep Wrangler 2.5L L4 Transfer Case Input Shaft Seal Transfer Case 6.45
    1986 Acura Integra LS 1.8L L4 Fuel/Air Fuel Cap (Regular) 4.15
    2000 Ford Escort 2.0L L4 Brake System Right Caliper Assembly Front 32.85
    2004 Dodge Neon SE 2.0L L4 Clutch Clutch Release Bearing 25.75
    1998 BMW 325I 2.5L L6 Steering Rack and Pinion Bellow Kit 19.25
    2001 Acura Integra GS 1.8L L4 Electrical Voltage Regulator 215.75
    2001 Audi S4 2.7L V6 Engine Timing Belt 35.95
    2002 Audi A4 Quattro 1.8L Turbo Exhaust Muffler Hanger 3.35
    2002 Chevrolet Silverado 2500 5.3L V8 Cooling System Radiator w/Air Tube - w/TOC 215.75
    2002 Acura NSX 3.0L V6 Engine Oil Drain Plug 1.35
    2002 Dodge Dakota 3.9L V6 Electrical Circuit Breaker 3.25
    2004 Dodge Neon SE 2.0L L4 Brake System Brake Pad 20.55
    2004 Honda Civic EX 1.7L L4 Electrical Fusible Link 3.35
    2002 Dodge Dakota 3.9L V6 Electrical Circuit Breaker 3.45
    2004 Honda Civic EX 1.7L L4 Transmission-Manual Differential Bearing 36.75
    1998 Toyota Corolla 1.8L L4 Cooling System Thermostat Standard Temperature 9.35
    2002 Audi A4 Quattro 1.8L Turbo Electrical Cooling Fan Sensor 8.65
    2002 Acura NSX 3.0L V6 Engine Oil Pump Seal 12.55
    2004 Dodge Neon SE 2.0L L4 Brake System Master Cylinder w/o ABS w/2 Wheel 102.95
    2002 Acura NSX 3.0L V6 Engine Valve Stem Oil Seal 1.75
    2002 Dodge Dakota 3.9L V6 Electrical Fuse 0.40
    1998 Toyota Corolla 1.8L L4 Cooling System Regular Thermostat 11.15
  21. Close the forms and return to your programming environment

Order Processing

Order processing consists of receiving requests from a customer and finding the items that the customer wants. To make this easy, as mentioned already, we created a form that allows the user to select the year, the make, the model, and the item's category. Once these selections are made, a list view displays the items that are available based on these criteria. To select an item and make it part of the order, the user can double-click it in the list view. This action copies the item by its item number, its name, and its unit price. It also sets its quantity to 1. The user can also change the quantity.

The calculations are made automatically so the user doesn't have to click a button or use a calculator.

Practical Learning Practical Learning: Processing Orders

  1. Display the OrderProcessing form
  2. Double-click the Year combo box and implement its SelectedIndexChanged event as follows:
     
    private void cboYears_SelectedIndexChanged(object sender, System.EventArgs e)
    {
    	string strYearSelected = this.cboYears.Text;
    	string strMake = null;
    	XmlDocument docXML = new XmlDocument();
    		
    	Text = strYearSelected;
    	// Open the Parts.xml file
    	docXML.Load("Parts.xml");
    			 
    	// We will empty the Make combo box to add a new list
    	this.cboMakes.Items.Clear();
    // We will empty the Model combo box because the car is about to be changed
    	this.cboModels.Items.Clear();
    	// Also empty the list of available parts
    	this.lvwAvailableParts.Items.Clear();
    	 
    	// Create a list of the nodes whose names are CarYear
    	XmlNodeList nodYears = docXML.GetElementsByTagName("CarYear");
    	// Create a list of the nodes whose names are Make
    	XmlNodeList nodMakes = docXML.GetElementsByTagName("Make");
    
    	// Check every CarYear node to see if its 
    	// value matches the selected year
    	for(int i = 0; i < nodYears.Count; i++)
    	{
    		// If the CarYear of the current node is the same as the
    	// selected year, add its corresponding make to the Make combo box
    		if( nodYears[i].InnerXml.Equals(strYearSelected) )
    		{
    			strMake = nodMakes[i].InnerText;
    	// Before adding the Make to the list, make sure that it doesn't
    			// exist already in the combo box
    			if( !this.cboMakes.Items.Contains(strMake) )
    				this.cboMakes.Items.Add(strMake);
    		}
    	}
    }
  3. Return to the Order Processing form and double-click the Make combo box
  4. Implement its SelectedIndexChanged event as follows:
     
    private void cboMakes_SelectedIndexChanged(object sender, System.EventArgs e)
    {
    	// Get the year that was selected
    	string strYearSelected = this.cboYears.Text;
    	// Get the make that is selected
    	string strMakeSelected = this.cboMakes.Text;
    	// We will need a model string
    	string strModel = null;
    	// We will use a reference to the XML document
    	XmlDocument docXML = new XmlDocument();
    			 
    	// Open the Parts.xml file
    	docXML.Load("Parts.xml");
    			 
    	// We will empty the Model combo box to add a new list
    	this.cboModels.Items.Clear();
    	// Also empty the list of available parts
    	this.lvwAvailableParts.Items.Clear();
    
    	// Create a list of the nodes we will need to locate
    	XmlNodeList nodYears  = docXML.GetElementsByTagName("CarYear");
    	XmlNodeList nodMakes  = docXML.GetElementsByTagName("Make");
    	XmlNodeList nodModels = docXML.GetElementsByTagName("Model");
    
    	// Check every CarYear node to see if its 
    	// value matches the selected year
    	for(int i = 0; i < nodYears.Count; i++)
    	{
    		// If the CarYear of the current node is the same as the
    	// selected year, check its corresponding make to see whether
    		// it matches the selected Make
    	// If both the year and the make selected match, then add the
    		// corresponding model to the Model combo box
    		if( (nodYears[i].InnerXml.Equals(strYearSelected)) &&
    			(nodMakes[i].InnerXml.Equals(strMakeSelected)) )
    		{
    			strModel = nodModels[i].InnerText;
    		// Before adding the model to the Model combo box, make sure 
    			// that it doesn't exist already in the list
    			if( this.cboModels.Items.Contains(strModel) )
    				break;
    			else // If it doesn't, then add it
    				this.cboModels.Items.Add(strModel);
    		}
    	}
    }
  5. Return to the Order Processing form and double-click the Model combo box
  6. Implement its SelectedIndexChanged event as follows:
     
    private void cboModels_SelectedIndexChanged_1(object sender, System.EventArgs e)
    {
    	// Get the year that was selected
    	 string strYearSelected = this.cboYears.Text;
    	 // Get the make that is selected
    	 string strMakeSelected = this.cboMakes.Text;
    	 // We will need a model string
    	 string strModelSelected = this.cboModels.Text;
    
    	 // We will use a reference to the XML document
    	 XmlDocument docXML = new XmlDocument();		 
    	 // Open the Parts.xml file
    	 docXML.Load("Parts.xml");	 
    	 
    	 // Empty the Category combo box
    	 this.cboCategories.Items.Clear();
    	 // Empty the list of available parts
    	 this.lvwAvailableParts.Items.Clear();
    
    	 // Create a list of the nodes we will need to locate
    	 XmlNodeList nodYears     = docXML.GetElementsByTagName("CarYear");
    	 XmlNodeList nodMakes     = docXML.GetElementsByTagName("Make");
    	 XmlNodeList nodModels    = docXML.GetElementsByTagName("Model");
    	 XmlNodeList nodPartNames = docXML.GetElementsByTagName("PartName");
    
    	 // Check every CarYear node to see if its 
    	 // value matches the selected year
    	 for(int i = 0; i < nodYears.Count; i++)
    	 {
    		 // If the CarYear of the current node is the same as the
    	// selected year, check its corresponding make and model to see whether
    		 // they match the selected Make and Model
    		 if( (nodYears[i].InnerXml.Equals(strYearSelected)) &&
    			 (nodMakes[i].InnerXml.Equals(strMakeSelected)) &&
    			 (nodModels[i].InnerXml.Equals(strModelSelected)) )
    		 {
    	 // If you find a part that match the year, the make and the model selected,
    	 // then retrieve the (first/only) attribute of the Part Name element
    		XmlAttribute nodCategory = nodPartNames[i].Attributes["Category"];
    			 // Add the category to the Categories combo box
    		 string strCategory = nodCategory.InnerText;
    		 // Before adding the model to the Model combo box, make sure 
    			 // that it doesn't exist already in the list
    			 if( this.cboCategories.Items.Contains(strCategory) )
    				 break;
    			 else // If it doesn't, then add it
    				 this.cboCategories.Items.Add(strCategory);
    		 }
    	 }
    }
  7. Return to the Order Processing form and double-click the Category combo box
  8. Implement its SelectedIndexChanged event as follows:
     
    private void cboCategories_SelectedIndexChanged(object sender, System.EventArgs e)
    {
    	// Get the values the user has selected
    	string strYearSelected = this.cboYears.Text;
    	string strMakeSelected = this.cboMakes.Text;
    	string strModelSelected = this.cboModels.Text;
    	string strCategorySelected = this.cboCategories.Text;
    			 
    	// Open the Parts.xml file
    	XmlDocument docXML = new XmlDocument();
    	docXML.Load("Parts.xml");
    			 
    	// Empty the list of available parts
    	this.lvwAvailableParts.Items.Clear();
    		 
    	// Create a list of the nodes we will need to locate
    	XmlNodeList nodYears     = docXML.GetElementsByTagName("CarYear");
    	XmlNodeList nodMakes     = docXML.GetElementsByTagName("Make");
    	XmlNodeList nodModels    = docXML.GetElementsByTagName("Model");
    	XmlNodeList nodPartNbr   = docXML.GetElementsByTagName("PartNumber");
    	XmlNodeList nodPartNames = docXML.GetElementsByTagName("PartName");
    	XmlNodeList nodPrices    = docXML.GetElementsByTagName("UnitPrice");
    
    	// Check every CarYear node to see if its 
    	// value matches the selected year
    	for(int i = 0; i < nodYears.Count; i++)
    	{
    	XmlAttribute nodCategory = nodPartNames[i].Attributes["Category"];
    	// Find the year, make, model, and category that match the selected
    		if( (nodYears[i].InnerXml.Equals(strYearSelected)) &&
    			(nodMakes[i].InnerXml.Equals(strMakeSelected)) &&
    			(nodModels[i].InnerXml.Equals(strModelSelected)) &&
    			(nodCategory.InnerText.Equals(strCategorySelected)) )
    		{
    		// Create a list view item of the part of the current model
    	ListViewItem itmPart = new ListViewItem(nodPartNbr[i].InnerText, 0);
    			itmPart.SubItems.Add(nodPartNames[i].InnerText);
    			itmPart.SubItems.Add(nodPrices[i].InnerText);
    			// And display that list to the list view control
    			this.lvwAvailableParts.Items.Add(itmPart);
    		}
    	}
    }
  9. In Class View, expand CPA3 and CPA3
  10. Right-click OrderProcessing -> Add -> Add Method...
  11. Set the Method Access to internal
  12. Set the Return Type to void
  13. Set the Method Name to CalculateTotalOrder
     
  14. Click Finish and implement the method as follows:
     
    internal void CalculateTotalOrder()
    {
    	decimal subTotal1, subTotal2, subTotal3,
    		subTotal4, subTotal5, subTotal6;
    	decimal orderTotal;
    
    	// Retrieve the value of each sub total
    	subTotal1 = decimal.Parse(this.txtSubTotal1.Text);
    	subTotal2 = decimal.Parse(this.txtSubTotal2.Text);
    	subTotal3 = decimal.Parse(this.txtSubTotal3.Text);
    	subTotal4 = decimal.Parse(this.txtSubTotal4.Text);
    	subTotal5 = decimal.Parse(this.txtSubTotal5.Text);
    	subTotal6 = decimal.Parse(this.txtSubTotal6.Text);
    
    	// Calculate the total value of the sub totals
    	orderTotal = subTotal1 + subTotal2 + subTotal3 + 
    		subTotal4 + subTotal5 + subTotal6;
    			
    	// Display the total order in the appropriate text box
    	this.txtTotalOrder.Text = orderTotal.ToString("F");
    }
  15. Display the Order Processing form
  16. Click the Available Parts list view. In the Properties window, click the Events button Events and double-click the DoubleClick field
  17. Implement the event as follows:
     
    private void lvwAvailableParts_DoubleClick(object sender, System.EventArgs e)
    {
    	ListViewItem itmSelectedPart = this.lvwAvailableParts.SelectedItems[0];
    			 
    	// Check if the first empty row in the Order Processing section
    	// and fill it up with the newly selected item
    	if( this.txtPartNumber1.Text == "" )
    	{
    		this.txtPartNumber1.Text = itmSelectedPart.Text;
    		this.txtPartName1.Text   = itmSelectedPart.SubItems[1].Text;
    		this.txtUnitPrice1.Text  = itmSelectedPart.SubItems[2].Text;
    		this.txtQuantity1.Text   = "1";
    		this.txtSubTotal1.Text   = itmSelectedPart.SubItems[2].Text;
    		this.chkKeepRemove1.Enabled = true;
    		this.chkKeepRemove1.Checked = true;
    		this.txtQuantity1.Focus();
    	}
    	else if( this.txtPartNumber2.Text == "" )
    	{
    		this.txtPartNumber2.Text = itmSelectedPart.Text;
    		this.txtPartName2.Text   = itmSelectedPart.SubItems[1].Text;
    		this.txtUnitPrice2.Text  = itmSelectedPart.SubItems[2].Text;
    		this.txtQuantity2.Text   = "1";
    		this.txtSubTotal2.Text   = itmSelectedPart.SubItems[2].Text;
    		this.chkKeepRemove2.Enabled = true;
    		this.chkKeepRemove2.Checked = true;
    		this.txtQuantity2.Focus();
    	}
    	else if( this.txtPartNumber3.Text == "" )
    	{
    		this.txtPartNumber3.Text = itmSelectedPart.Text;
    		this.txtPartName3.Text   = itmSelectedPart.SubItems[1].Text;
    		this.txtUnitPrice3.Text  = itmSelectedPart.SubItems[2].Text;
    		this.txtQuantity3.Text   = "1";
    		this.txtSubTotal3.Text   = itmSelectedPart.SubItems[2].Text;
    		this.chkKeepRemove3.Enabled = true;
    		this.chkKeepRemove3.Checked = true;
    		this.txtQuantity3.Focus();
    	}
    	else if( this.txtPartNumber4.Text == "" )
    	{
    		this.txtPartNumber4.Text = itmSelectedPart.Text;
    		this.txtPartName4.Text   = itmSelectedPart.SubItems[1].Text;
    		this.txtUnitPrice4.Text  = itmSelectedPart.SubItems[2].Text;
    		this.txtQuantity4.Text   = "1";
    		this.txtSubTotal4.Text   = itmSelectedPart.SubItems[2].Text;
    		this.chkKeepRemove4.Enabled = true;
    		this.chkKeepRemove4.Checked = true;
    		this.txtQuantity4.Focus();
    	}
    	else if( this.txtPartNumber5.Text == "" )
    	{
    		this.txtPartNumber5.Text = itmSelectedPart.Text;
    		this.txtPartName5.Text   = itmSelectedPart.SubItems[1].Text;
    		this.txtUnitPrice5.Text  = itmSelectedPart.SubItems[2].Text;
    		this.txtQuantity5.Text   = "1";
    		this.txtSubTotal5.Text   = itmSelectedPart.SubItems[2].Text;
    		this.chkKeepRemove5.Enabled = true;
    		this.chkKeepRemove5.Checked = true;
    		this.txtQuantity5.Focus();
    	}
    	else if( this.txtPartNumber6.Text == "" )
    	{
    		this.txtPartNumber6.Text = itmSelectedPart.Text;
    		this.txtPartName6.Text   = itmSelectedPart.SubItems[1].Text;
    		this.txtUnitPrice6.Text  = itmSelectedPart.SubItems[2].Text;
    		this.txtQuantity6.Text   = "1";
    		this.txtSubTotal6.Text   = itmSelectedPart.SubItems[2].Text;
    		this.chkKeepRemove6.Enabled = true;
    		this.chkKeepRemove6.Checked = true;
    		this.txtQuantity6.Focus();
    	}
    	else
    		return;
    
    	// Calculate the current total order and update the order
    	CalculateTotalOrder();
    }
  18. Display the Order Processing form and click the first text box under Qty
  19. In the Properties window and in the Events section, double-click the Leave field
  20. Return to the form, click each of the other Qty text boxes, and in the Properties window, click the Leave field of each Qty
  21. Implement their events as follows:
     
    private void txtQuantity1_Leave(object sender, System.EventArgs e)
    {
    	int qty = 0;
    	decimal unitPrice = 0.00M, subTotal = 0.00M;
    	
    	try 
    	{
    		// Get the quantity of the current item
    		qty = int.Parse(this.txtQuantity1.Text);
    	}
    	catch(FormatException)
    	{
    MessageBox.Show("The value you provided for the quantity of the item is invalid" +
    			"\nPlease try again");
    	}
    			
    	try 
    	{
    		// Get the unit price of the current item
    		unitPrice = decimal.Parse(this.txtUnitPrice1.Text);
    	}
    	catch(FormatException)
    	{
    		MessageBox.Show("The unit price you provided for item is invalid" +
    			"\nPlease try again");
    	}
    	// Calculate the current sub total
    	subTotal = qty * unitPrice;
    
    	// Display the new sub total in the corresponding text box
    	this.txtSubTotal1.Text = subTotal.ToString("F");
    	// Update the order
    	CalculateTotalOrder();
    }
    
    private void txtQuantity2_Leave(object sender, System.EventArgs e)
    {
    	int qty = 0;
    	decimal unitPrice = 0.00M, subTotal = 0.00M;
    			
    	try 
    	{
    		qty = int.Parse(this.txtQuantity2.Text);
    	}
    	catch(FormatException)
    	{
    MessageBox.Show("The value you provided for the quantity of the item is invalid" +
    			"\nPlease try again");
    	}
    			
    	try 
    	{
    		unitPrice = decimal.Parse(this.txtUnitPrice2.Text);
    	}
    	catch(FormatException)
    	{
    		MessageBox.Show("The unit price you provided for item is invalid" +
    			"\nPlease try again");
    	}
    	subTotal = qty * unitPrice;
    
    	this.txtSubTotal2.Text = subTotal.ToString("F");
    	CalculateTotalOrder();
    }
    
    private void txtQuantity3_Leave(object sender, System.EventArgs e)
    {
    	int qty = 0;
    	decimal unitPrice = 0.00M, subTotal = 0.00M;
    			
    	try 
    	{	
    		qty = int.Parse(this.txtQuantity3.Text);
    	}
    	catch(FormatException)
    	{
    MessageBox.Show("The value you provided for the quantity of the item is invalid" +
    			"\nPlease try again");
    	}
    			
    	try 
    	{
    		unitPrice = decimal.Parse(this.txtUnitPrice3.Text);
    	}
    	catch(FormatException)
    	{
    		MessageBox.Show("The unit price you provided for item is invalid" +
    			"\nPlease try again");
    	}
    	subTotal = qty * unitPrice;
    
    	this.txtSubTotal3.Text = subTotal.ToString("F");
    	CalculateTotalOrder();
    }
    
    private void txtQuantity4_Leave(object sender, System.EventArgs e)
    {
    	int qty = 0;
    	decimal unitPrice = 0.00M, subTotal = 0.00M;
    			
    	try 
    	{			
    		qty = int.Parse(this.txtQuantity4.Text);
    	}
    	catch(FormatException)
    	{
    MessageBox.Show("The value you provided for the quantity of the item is invalid" +
    			"\nPlease try again");
    	}
    	
    	try 
    	{
    		unitPrice = decimal.Parse(this.txtUnitPrice4.Text);
    	}
    	catch(FormatException)
    	{
    		MessageBox.Show("The unit price you provided for item is invalid" +
    			"\nPlease try again");
    	}
    	subTotal = qty * unitPrice;
    
    	this.txtSubTotal4.Text = subTotal.ToString("F");
    	CalculateTotalOrder();
    }
    
    private void txtQuantity5_Leave(object sender, System.EventArgs e)
    {
    	int qty = 0;
    	decimal unitPrice = 0.00M, subTotal = 0.00M;
    			
    	try 
    	{	
    		qty = int.Parse(this.txtQuantity5.Text);
    	}
    	catch(FormatException)
    	{
    MessageBox.Show("The value you provided for the quantity of the item is invalid" +
    			"\nPlease try again");
    	}
    	
    	try 
    	{
    		unitPrice = decimal.Parse(this.txtUnitPrice5.Text);
    	}
    	catch(FormatException)
    	{
    		MessageBox.Show("The unit price you provided for item is invalid" +
    			"\nPlease try again");
    	}
    	subTotal = qty * unitPrice;
    
    	this.txtSubTotal5.Text = subTotal.ToString("F");
    	CalculateTotalOrder();
    }
    
    private void txtQuantity6_Leave(object sender, System.EventArgs e)
    {
    	int qty = 0;
    	decimal unitPrice = 0.00M, subTotal = 0.00M;
    			
    	try 
    	{	
    		qty = int.Parse(this.txtQuantity6.Text);
    	}
    	catch(FormatException)
    	{
    MessageBox.Show("The value you provided for the quantity of the item is invalid" +
    				"\nPlease try again");
    	}
    			
    	try 
    	{
    		unitPrice = decimal.Parse(this.txtUnitPrice6.Text);
    	}
    	catch(FormatException)
    	{
    		MessageBox.Show("The unit price you provided for item is invalid" +
    			"\nPlease try again");
    	}
    	subTotal = qty * unitPrice;
    
    	this.txtSubTotal6.Text = subTotal.ToString("F");
    	CalculateTotalOrder();
    }
  22. Display the Order Processing form and double-click the most top check box
  23. Return to the form and double-click each of the other check boxes
  24. Implement their events as follows:
     
    private void chkKeepRemove1_CheckedChanged(object sender, System.EventArgs e)
    {
    	// If the check box was unchecked
    	if( this.chkKeepRemove1.Checked == false ) 
    	{
    		// Reset the controls of the current item
    		this.txtPartNumber1.Text      = "";
    		this.txtPartName1.Text = "";
    		this.txtUnitPrice1.Text   = "";
    		this.txtQuantity1.Text    = "0";
    		this.txtSubTotal1.Text    = "0.00";
    		this.chkKeepRemove1.Checked     = false;
    		this.chkKeepRemove1.Enabled     = false;
    		// Re-calculate the total order to update it
    		CalculateTotalOrder();
    	}
    }
    
    private void chkKeepRemove2_CheckedChanged(object sender, System.EventArgs e)
    {
    	// If the check box was unchecked
    	if( this.chkKeepRemove2.Checked == false ) 
    	{
    		// Reset the controls of the current item
    		this.txtPartNumber2.Text      = "";
    		this.txtPartName2.Text = "";
    		this.txtUnitPrice2.Text   = "";
    		this.txtQuantity2.Text    = "0";
    		this.txtSubTotal2.Text    = "0.00";
    		this.chkKeepRemove2.Checked     = false;
    		this.chkKeepRemove2.Enabled     = false;
    		// Re-calculate the total order to update it
    		CalculateTotalOrder();
    	}
    }
    
    private void chkKeepRemove3_CheckedChanged(object sender, System.EventArgs e)
    {
    	// If the check box was unchecked
    	if( this.chkKeepRemove3.Checked == false ) 
    	{
    		// Reset the controls of the current item
    		this.txtPartNumber3.Text      = "";
    		this.txtPartName3.Text = "";
    		this.txtUnitPrice3.Text   = "";
    		this.txtQuantity3.Text    = "0";
    		this.txtSubTotal3.Text    = "0.00";
    		this.chkKeepRemove3.Checked     = false;
    		this.chkKeepRemove3.Enabled     = false;
    		// Re-calculate the total order to update it
    		CalculateTotalOrder();
    	}
    }
    
    private void chkKeepRemove4_CheckedChanged(object sender, System.EventArgs e)
    {
    	// If the check box was unchecked
    	if( this.chkKeepRemove4.Checked == false ) 
    	{
    		// Reset the controls of the current item
    		this.txtPartNumber4.Text      = "";
    		this.txtPartName4.Text = "";
    		this.txtUnitPrice4.Text   = "";
    		this.txtQuantity4.Text    = "0";
    		this.txtSubTotal4.Text    = "0.00";
    		this.chkKeepRemove4.Checked     = false;
    		this.chkKeepRemove4.Enabled     = false;
    		// Re-calculate the total order to update it
    		CalculateTotalOrder();
    	}
    }
    
    private void chkKeepRemove5_CheckedChanged(object sender, System.EventArgs e)
    {
    	// If the check box was unchecked
    	if( this.chkKeepRemove5.Checked == false ) 
    	{
    		// Reset the controls of the current item
    		this.txtPartNumber5.Text      = "";
    		this.txtPartName5.Text = "";
    		this.txtUnitPrice5.Text   = "";
    		this.txtQuantity5.Text    = "0";
    		this.txtSubTotal5.Text    = "0.00";
    		this.chkKeepRemove5.Checked     = false;
    		this.chkKeepRemove5.Enabled     = false;
    		// Re-calculate the total order to update it
    		CalculateTotalOrder();
    	}
    }
    
    private void chkKeepRemove6_CheckedChanged(object sender, System.EventArgs e)
    {
    	// If the check box was unchecked
    	if( this.chkKeepRemove6.Checked == false ) 
    	{
    		// Reset the controls of the current item
    		this.txtPartNumber6.Text      = "";
    		this.txtPartName6.Text = "";
    		this.txtUnitPrice6.Text   = "";
    		this.txtQuantity6.Text    = "0";
    		this.txtSubTotal6.Text    = "0.00";
    		this.chkKeepRemove6.Checked     = false;
    		this.chkKeepRemove6.Enabled     = false;
    		// Re-calculate the total order to update it
    		CalculateTotalOrder();
    	}
    }
  25. Execute the application to test it
 

Saving an Order

When a order has been placed and it is ready, the user can save it to a file. The orders for each day are stored in their own file so the management can review daily sales. This can be done automatically. If not, the user can save each order in its own file or in any existing file.

Practical Learning Practical Learning: Saving an Order

  1. Display the Order Processing form and double-click the Save button
  2. Implement its Click event as follows:
     
    private void btnSave_Click(object sender, System.EventArgs e)
    {
    	string strFilename = this.dtpFilename.Text + ".xml";
    	XmlDocument docXML = new XmlDocument();
    	string strContent = null;
    	string strTotalOrder = this.txtTotalOrder.Text;
    	string strParentOrder = null;
    
    	if( this.chkKeepRemove1.Checked == true )
    	{
    		strContent = strContent +
    		"<PartSold><PartNumber>" + this.txtPartNumber1.Text + "</PartNumber>" +
    			"<PartName>" + this.txtPartName1.Text + "</PartName>" +
    			"<UnitPrice>" + this.txtUnitPrice1.Text + "</UnitPrice>" +
    			"<Qty>" + this.txtQuantity1.Text + "</Qty>" +
    			"<SubTotal>" + this.txtSubTotal1.Text + "</SubTotal></PartSold>";
    	}
    
    	if( this.chkKeepRemove2.Checked == true )
    	{
    		strContent = strContent +
    		"<PartSold><PartNumber>" + this.txtPartNumber2.Text + "</PartNumber>" +
    			"<PartName>" + this.txtPartName2.Text + "</PartName>" +
    			"<UnitPrice>" + this.txtUnitPrice2.Text + "</UnitPrice>" +
    			"<Qty>" + this.txtQuantity2.Text + "</Qty>" +
    			"<SubTotal>" + this.txtSubTotal2.Text + "</SubTotal></PartSold>";
    	}
    
    	if( this.chkKeepRemove3.Checked == true )
    	{
    		strContent = strContent +
    		"<PartSold><PartNumber>" + this.txtPartNumber3.Text + "</PartNumber>" +
    			"<PartName>" + this.txtPartName3.Text + "</PartName>" +
    			"<UnitPrice>" + this.txtUnitPrice3.Text + "</UnitPrice>" +
    			"<Qty>" + this.txtQuantity3.Text + "</Qty>" +
    			"<SubTotal>" + this.txtSubTotal3.Text + "</SubTotal></PartSold>";
    	}
    
    	if( this.chkKeepRemove4.Checked == true )
    	{
    		strContent = String.Concat(strContent,
    		"<PartSold><PartNumber>", this.txtPartNumber4.Text, "</PartNumber>",
    			"<PartName>", this.txtPartName4.Text, "</PartName>",
    			"<UnitPrice>", this.txtUnitPrice4.Text, "</UnitPrice>",
    			"<Qty>", this.txtQuantity4.Text, "</Qty>",
    			"<SubTotal>", this.txtSubTotal4.Text, "</SubTotal></PartSold>");
    	}
    
    	if( this.chkKeepRemove5.Checked == true )
    	{
    		strContent = String.Concat(strContent, 
    		"<PartSold><PartNumber>", this.txtPartNumber5.Text, "</PartNumber>",
    			"<PartName>", this.txtPartName5.Text, "</PartName>",
    			"<UnitPrice>", this.txtUnitPrice5.Text, "</UnitPrice>",
    			"<Qty>", this.txtQuantity5.Text, "</Qty>",
    			"<SubTotal>", this.txtSubTotal5.Text, "</SubTotal></PartSold>");
    	}
    
    	if( this.chkKeepRemove6.Checked == true )
    	{
    		strContent = String.Concat(strContent, 
    		"<PartSold><PartNumber>", this.txtPartNumber6.Text, "</PartNumber>",
    			"<PartName>", this.txtPartName6.Text, "</PartName>",
    			"<UnitPrice>", this.txtUnitPrice6.Text, "</UnitPrice>",
    			"<Qty>", this.txtQuantity6.Text, "</Qty>",
    			"<SubTotal>", this.txtSubTotal6.Text, "</SubTotal></PartSold>");
    	}
    
    	if( File.Exists(strFilename) )
    	{
    		// If the file exists already, open it
    		docXML.Load(strFilename);
    		// Get a reference to the root element
    		XmlElement elmRoot = docXML.DocumentElement;
    		// Get a reference to the last child of the root
    		XmlNode nodLastOrder = elmRoot.LastChild;
    		// Get the OrderNumber attribute of the last order and increment it by 1
    int NewOrderNumber = int.Parse(nodLastOrder.Attributes["OrderNumber"].InnerText) + 1;
    
    		// Create a new order as an element
    		XmlElement elmNewOrder = docXML.CreateElement("Order");
    		// Add its attributes
    		elmNewOrder.SetAttribute("OrderNumber", NewOrderNumber.ToString());
    		elmNewOrder.SetAttribute("TotalOrder", strTotalOrder);
    		elmNewOrder.InnerXml = strContent;
    		docXML.DocumentElement.AppendChild(elmNewOrder);
    		docXML.Save(strFilename);
    	}
    	else
    	{
    		// If the file doesn't exist, get ready to create it
    	strParentOrder = "<Order OrderNumber=\"1\" TotalOrder=\"" + strTotalOrder, "\">";
    
    		// If the file doesn't exist, create it
    		docXML.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
    			"<Orders>" +
    			strParentOrder + strContent + "</Order></Orders>");
    		docXML.Save(strFilename);
    	}
    
    	// Reset the Order Processing form
    	this.lvwAvailableParts.Items.Clear();
    	this.cboCategories.SelectedIndex = -1;
    	this.cboModels.SelectedIndex     = -1;
    	this.cboMakes.SelectedIndex      = -1;
    	this.cboYears.SelectedIndex      = -1;
    	this.chkKeepRemove1.Checked = false;
    	this.chkKeepRemove2.Checked = false;
    	this.chkKeepRemove3.Checked = false;
    	this.chkKeepRemove4.Checked = false;
    	this.chkKeepRemove5.Checked = false;
    	this.chkKeepRemove6.Checked = false;
    	this.CalculateTotalOrder();
    }
  3. Execute the application
  4. To simulate some sales, create the following orders
     
    First Order - Date Saved: 16 June 1998
    Year Make Model Category Item Name Qty
    1986 Acura Integra LS 1.8L L4 Electrical Alternator 1
    1986 Acura Integra LS 1.8L L4 Fuel/Air Fuel Cap (Regular) 4
    Second Order - Date Saved: 24 August 2000
    1998 Toyota Corolla 1.8L L4 Cooling System Radiator 2
    1998 Jeep Wrangler 2.5L L4 Transfer Case Input Shaft Seal Transfer Case 4
    Third Order - Date Saved: 16 June 1998
    2002 Chevrolet Silverado 2500 5.3L V8 Ignition Spark Plugs 4
    2002 Dodge Dakota 3.9L V6 Electrical Starter Motor 1
    2002 Acura NSX 3.0L V6 Engine Oil Filter 2
    1998 BMW 325I 2.5L L6 Steering Rack and Pinion Bellow Kit 2
    Fourth Order - Date Saved: 24 August 2000
    2000 Ford Escort 2.0L L4 Ignition Crankshaft Position Sensor 2
    2000 Ford Escort 2.0L L4 Brake System Right Caliper Assembly Front 1
    Fifth Order - Date Saved: 21 January 2005
    2004 Dodge Neon SE 2.0L L4 Engine Oil Pump 1
    2004 Dodge Neon SE 2.0L L4 Clutch Clutch Release Bearing 2
    2004 Dodge Neon SE 2.0L L4 Cooling System Radiator Fan Assembly 1
     
    College Park Auto-Parts - Order Processing
  5. Close the forms
  6. Preview the saved orders in your browser
     
  7. Return to your programming environment
 

Home Copyright © 2004-2010 FunctionX, Inc.