Home

Introduction to the Records of a Data Set

   

The Rows of a Table

 

Introduction to Records

In our description of tables, we saw that a table was made of one or many columns that represented some categories of data. Here is an example of a table with a few columns:

Shelf Number Title Director Length Year Rating
           
           

After creating such a table and its columns, you (actually the user) can enter values in the table to make it a valuable list. Filling up a table with values is referred to as data entry.

Practical Learning: Introducing Data Sets

  1. Start Microsoft Visual Studio
  2. Create a new Windows Forms Application named CollegeParkAutoParts2
  3. In the Solution Explorer, right-click Form1.cs and click Rename
  4. Type CollegeParkAutoParts.cs and press Enter twice to display the form
  5. From the Components section of the Toolbox, click ImageList and click the form
  6. In the Properties window, click (Name) and type imgAutoParts
  7. Click the ellipsis button of the Images field
  8. In the Image Collection Editor, click Add
  9. Locate the folder that contains the resources for these lessons and display it in the Look In combo box
  10. Select the following icons: Sign1, Sign2, Cliper1, Cliper2, Rulers1, Rulers2, Graph1, Graph2, Tool1, and Tool2
  11. Click Open
     
    Image Collection Editor
  12. Click OK
  13. Design the form as follows:
     
    College Park Auto Parts - Form Design
    Control Text Name Other Properties
    Label Label College Park Auto-Parts   Font: Times New Roman, 20.25pt, style=Bold
    ForeColor: Blue
    Panel Panel     Height: 2
    GroupBox Group Box Part Identification    
    TreeView Tree View   tvwAutoParts ImageList: imgAutoParts
    GroupBox Group Box Available Parts    
    ListView List View   lvwAutoParts FullRowSelect: True
    GridLines: True
    View: Details
    Columns   (Name) Text TextAlign Width
    colPartNumber Part #    
    colPartName Part Name   300
    colUnitPrice Unit Price Right 80
    GroupBox Group Box Customer Order - Selected Parts    
    Label Label Part #    
    Label Label Part Name    
    Label Label Unit Price    
    Label Label Qty    
    Label Label Sub Total    
    TextBox Text Box   txtPartNumber  
    TextBox Text Box   txtPartName  
    TextBox Text Box 0.00 txtUnitPrice TextAlign: Right
    TextBox Text Box 0 txtQuantity TextAlign: Right
    TextBox Text Box 0.00 txtSubTotal TextAlign: Right
    Button Button Add/Select btnAdd
    ListView List View   lvwSelectedParts FullRowSelect: True
    GridLines: True
    View: Details
    Columns   (Name) Text TextAlign Width
    colPartNumberSelected Part #   45
    colPartNameSelected Part Name   274
    colUnitPriceSelected Unit Price Right 58
    colQuantitySelected Qty Right 28
    colSubTotalSelected Sub-Total Right 58
    GroupBox Group Box Order Summary    
    Button Button New Au&to Part... btnNewAutoPart  
    Label Label Receipt #:    
    TextBox Text Box txtSave  
    Button Button Save btnSave  
    Label Label Tax Rate:    
    TextBox Text Box 7.75 txtTaxRate TextAlign: Right
    Label Label %    
    Label Label Parts Total:    
    TextBox Text Box 0.00 txtPartsTotal TextAlign: Right
    Button Button &New Customer Order btnNewCustomerOrder  
    Label Label Receipt #:     
    TextBox Text Box   txtOpen  
    Button Button Save btnOpen  
    Label Label Tax Amount:    
    TextBox Text Box 0.00 txtTaxAmount TextAlign: Right
    Label Label Order Total:    
    TextBox Text Box 0.00 txtOrderTotal TextAlign: Right
    Button Button Close btnClose  
  14. Click the Available Parts list view
  15. In the Properties window, click the Events button and, in the Events section, double-click DoubleClick
  16. Implement the event as follows:
    private void lvwAutoParts_DoubleClick(object sender, EventArgs e)
    {
        ListViewItem lviAutoPart = lvwAutoParts.SelectedItems[0];
    
        if( (lvwAutoParts.SelectedItems.Count == 0) ||
            (lvwAutoParts.SelectedItems.Count > 1) )
                    return;
    
        txtPartNumber.Text = lviAutoPart.Text;
        txtPartName.Text = lviAutoPart.SubItems[1].Text;
        txtUnitPrice.Text = lviAutoPart.SubItems[2].Text;
    
        txtQuantity.Text = "1";
        txtSubTotal.Text = lviAutoPart.SubItems[2].Text;
    
        txtQuantity.Focus();
    }
  17. Return to the College Park Auto-Parts form
  18. Click the Unit Price text box and, in the Events section of the Properties window, double-click Leave
  19. Implement the event as follows:
    private void txtUnitPrice_Leave(object sender, EventArgs e)
    {
        double UnitPrice = 0.00D;
        int Quantity = 0;
        double SubTotal = 0.00D;
    
        try
        {
            UnitPrice = double.Parse(txtUnitPrice.Text);
        }
        catch (FormatException)
        {
            MessageBox.Show("Invalid Unit Price!");
        }
    
        try { Quantity = int.Parse(txtQuantity.Text); }
        catch (FormatException)
        {
            MessageBox.Show("Invalid Quandtity!");
        }
    
        SubTotal = UnitPrice * Quantity;
        txtSubTotal.Text = SubTotal.ToString("F");
    }
    
    internal void CalculateOrder()
    {
        double PartsTotal = 0.00;
        double TaxRate = 0.00;
        double TaxAmount = 0.00;
        double OrderTotal = 0.00;
    
        ListViewItem lviSelectedPart = lvwSelectedParts.Items[0];
    
        foreach (ListViewItem lvi in lvwSelectedParts.Items)
        {
            ListViewItem.ListViewSubItem SubItem = lvi.SubItems[4];
    
            PartsTotal += double.Parse(SubItem.Text);
        }
    
        try
        {
            TaxRate = double.Parse(txtTaxRate.Text) / 100;
        }
        catch (FormatException)
        {
            MessageBox.Show("Invalid Tax Rate");
        }
    
        TaxAmount = PartsTotal * TaxRate;
        OrderTotal = PartsTotal + TaxAmount;
    
        txtOrderTotal.Text = PartsTotal.ToString("F");
        txtTaxAmount.Text = TaxAmount.ToString("F");
        txtOrderTotal.Text = OrderTotal.ToString("F");
    }
  20. Return to the College Park Auto-Parts form and click the Qty text box
  21. In the Events section of the Properties, click Leave, then click the arrow of its combo box and select txtUnitPrice_Leave
  22. Return to the College Park Auto-Parts form, click the Selected Part list view (the list view in the bottom-right section of the form)
  23. In the Events section of the Properties window, double-click DoubleClick
  24. Implement the event as follows:
    private void lvwSelectedParts_DoubleClick(object sender, EventArgs e)
    {
        ListViewItem lviSelectedPart = lvwSelectedParts.SelectedItems[0];
    
        if( (lvwSelectedParts.SelectedItems.Count == 0) ||
            (lvwSelectedParts.SelectedItems.Count > 1) )
            return;
    
        txtPartNumber.Text = lviSelectedPart.Text;
        txtPartName.Text = lviSelectedPart.SubItems[1].Text;
        txtUnitPrice.Text = lviSelectedPart.SubItems[2].Text;
        txtQuantity.Text = lviSelectedPart.SubItems[3].Text;
        txtSubTotal.Text = lviSelectedPart.SubItems[4].Text;
    
        lvwSelectedParts.Items.Remove(lviSelectedPart);
        CalculateOrder();
    }

A Data Source and a Data Member for the Data Grid View

When creating an application, to deliver it to the user and make it ready for data entry, you can create one or more forms as we did in previous lessons. When it comes to a data set, the .NET Framework provides a control named data grid view. As opposed to a list view, instead of visually creating the columns and/or the items, you can specify the source of the records. This would equip the data grid view with the necessary columns and the records in the data set.

After creating a data grid view, you can assign it a data source, such as a DataSet object. At design time, to specify the data source of a data grid view, in the Properties window, select the object in the DataSource field. At run time, to specify a data source, assign the appropriate object to the DataSource property. Here is an example:

public class Exercise : Form
{
    DataGridView dgvStudents;

    DataSet dsRedOakHighSchool;
    DataTable tblRegistration;
    DataColumn colFirstName;
    DataColumn colLastName;
    DataColumn colGender;

    public Exercise()
    {
        InitializeComponent();
    }

    void InitializeComponent()
    {
        Text = "Students Records";
        dgvStudents = new DataGridView();
        dgvStudents.Location = new Point(12, 12);
        Controls.Add(dgvStudents);

        colFirstName = new DataColumn("First Name");
        colLastName = new DataColumn("Last Name");
        colGender = new DataColumn("Gender");

        tblRegistration = new DataTable("Student Registration");
        tblRegistration.Columns.Add(colFirstName);
        tblRegistration.Columns.Add(colLastName);
        tblRegistration.Columns.Add(colGender);

        dsRedOakHighSchool = new DataSet("Red Oak High School");
        dsRedOakHighSchool.Tables.Add(tblRegistration);

        dgvStudents.DataSource = dsRedOakHighSchool;
    }
}

To find out what the data source of a data grid view is, get the value of its DataSource property.

After assigning a data source, you should assign a data member to the data grid view. To visually specify the data members, in the Properties window of the data grid view, after setting the data source, access the DataMember field and click its arrowed button. Then, in the list, select an object, such as a table of a data set.

To programmatically specify the data member, after assigning the appropriate variable to the DataSource property, assign the name of the list, such as the object name of a table, to the DataMember property of the DataGridView object. Here is an example:

void InitializeComponent()
{
    Text = "Students Records";
    dgvStudents = new DataGridView();
    dgvStudents.Location = new Point(12, 12);
    Controls.Add(dgvStudents);

    colFirstName = new DataColumn("First Name");
    colLastName = new DataColumn("Last Name");
    colGender = new DataColumn("Gender");

    tblRegistration = new DataTable("Student Registration");
    tblRegistration.Columns.Add(colFirstName);
    tblRegistration.Columns.Add(colLastName);
    tblRegistration.Columns.Add(colGender);

    dsRedOakHighSchool = new DataSet("Red Oak High School");
    dsRedOakHighSchool.Tables.Add(tblRegistration);

    dgvStudents.DataSource = dsRedOakHighSchool;
    dgvStudents.DataMember = "Student Registration";
}

Once you have specified the data source and the data member, the columns would appear on the data grid view:

Practical LearningPractical Learning: Introducing Data Records

  1. To create a dialog box, on the main menu, click PROJECT -> Add Windows Form...
  2. Set the name to ItemsCategories and click Add
  3. From the Data section of the Toolbox, click DataSet and click the form
  4. On the Add Dataset dialog box, click the Untyped dataset radio button and click OK
  5. In the Properties window, change the characteristics of the data set as follows:
    DataSetName: Categories
    (Name): dsCategories
  6. Click the Tables field and click its ellipsis button
  7. In the Tables Collection Editor, click Add
  8. In the Properties list, change the characteristics of the table as follows:
    TableName: PartCategory
    (Name): tblPartCategory
  9. Click Columns and click its ellipsis button
  10. In the Columns Collection Editor, click Add
  11. Change the characteristics of the columns as follows:
    ColumnName: Category
    (Name): colCategory 
  12. Click Close and click Close
  13. Design the form as follows:
     
    College Park Auto-Parts: Categories
    Control Text Name Additional Properties
    DataGridView DataGridView   dgvCategoriess Anchor: Top, Bottom, Left, Right
    DataSource: dsCategories
    DataMember: Category
    Button Button Close btnClose Anchor: Bottom, Right
  14. To create a dialog box, on the main menu, click PROJECT -> Add Windows Form...
  15. Set the name to Makes and click Add
  16. From the Data section of the Toolbox, click DataSet and click the form
  17. On the Add Dataset dialog box, click the Untyped dataset radio button and click OK
  18. In the Properties window, change the characteristics of the data set as follows:
    DataSetName: Makes
    (Name): dsMakes
  19. Click the Tables field and click its ellipsis button
  20. In the Tables Collection Editor, click Add
  21. In the Properties list, change the characteristics of the table as follows:
    TableName: VehicleMake
    (Name): tblVehicleMake
  22. Click Columns and click its ellipsis button
  23. In the Columns Collection Editor, click Add
  24. Change the characteristics of the columns as follows:
    ColumnName: Make
    (Name): colMake 
  25. Click Close and click Close
  26. Design the form as follows:
     
    College Park Auto-Parts: Makes
    Control Text Name Additional Properties
    DataGridView DataGridView   dgvMakes Anchor: Top, Bottom, Left, Right
    DataSource: dsMakes
    DataMember: Makes
    Button Button Close btnClose Anchor: Bottom, Right
  27. To create a dialog box, on the main menu, click PROJECT -> Add Windows Form...
  28. Set the name to Models and click Add
  29. Display the list of makes form
  30. Right-click dsMakes and click Copy
  31. Display the Models form
  32. Right-click its body and click Paste
  33. From the Data section of the Toolbox, click DataSet and click the form
  34. On the Add Dataset dialog box, click the Untyped dataset radio button and click OK
  35. In the Properties window, change the characteristics of the data set as follows:
    DataSetName: Models
    (Name): dsModels
  36. Click the Tables field and click its ellipsis button
  37. In the Tables Collection Editor, click Add
  38. In the Properties list, change the characteristics of the table as follows:
    TableName: VehicleModel
    (Name): tblVehicleModel
  39. Click Columns and click its ellipsis button
  40. In the Columns Collection Editor, click Add
  41. Change the characteristics of the columns as follows:
    ColumnName: Make
    (Name): colMake
  42. In the Columns Collection Editor, click Add
  43. Change the characteristics of the columns as follows:
    ColumnName: Model
    (Name): colModel
  44. Click Close and click Close
  45. From the Data section of the Toolbox, click DataGridView and click the form
  46. In the Properties window, change its characteristics as follows:
    DataSource: dsModels
    DataMember: CarModel
  47. Right-click the data grid view on the form and click Edit Columns...
  48. Change the columns as follows:
     
    Selected Columns: HeaderText DataPropertyName ColumnType DataSource DisplayMember
    Make Make Make DataGridViewComboBoxColumn dsMakes VehicleMake.Make
    Model Model Model      
  49. Click OK
  50. Design the form as follows:
     
    College Partk Auto Parts: Models
    Control Text Name Additional Properties
    DataGridView DataGridView   dgvModels Anchor: Top, Bottom, Left, Right
    Button Button Close btnClose Anchor: Bottom, Right
  51. To create a new form, in the Solution Explorer, right-click CollegeParkAutoParts2 -> Add -> Windows Form...
  52. Set the Name to AutoParts and click Add
  53. Display the Models form and click dsMakes
  54. Press and hold Shift
  55. Click dsModels and release Shift 
  56. Press Ctrl + C
  57. Display the auto parts form
  58. Right-click its body and click Paste
  59. Display the Categories form
  60. Right-click dsCategories and click Copy
  61. Display the Auto Parts form
  62. Right-click its body and click Paste
  63. From the Data section of the Toolbox, click DataSet and click the form
  64. In the Add Dataset dialog box, click the Untyped dataset radio button and click OK
  65. In the Properties window, change the characteristics of the data set as follows:
    DataSetName: StoreItems
    (Name): dsStoreItems
  66. Click Tables and click its ellipsis button
  67. In the Properties list, change the characteristics of the table as follows:
    TableName: StoreItem
    (Name): tblStoreItem
  68. Click Columns and click its ellipsis button
  69. In the Columns Collection Editor, click Add continuously and create the columns as follows:
     
    ColumnName (Name)
    PartNumber colPartNumber
    Year colYear
    Make colMake
    Model colModel
    Category colCategory
    PartName colPartName
    UnitPrice colUnitPrice
  70. Click Close and click Close
  71. From the Data section of the Toolbox, click DataGridView and click the form
  72. In the Properties window, change its characteristics as follows:
    DataSource: dsStoreItems
    DataMember: StoreItems
  73. Under the Properties window, click Edit Columns... and change the columns as follows:

    Selected Columns: HeaderText DataPropertyName ColumnType DataSource DisplayMember Width
    Part # Part # PartNumber       50
    Year Year Year       40
    Make Make Make DataGridViewComboBoxColumn dsMakes VehicleMake.Make 85
    Model Model Model DataGridViewComboBoxColumn dsModels VehicleModel.Model 130
    Category Category Category DataGridViewComboBoxColumn dsCategories PartCategory.Category 120
    Part Name Part Name/Description PartName       185
    Unit Price Unit Price UnitPrice       65

  74. Click OK
  75. Design the form as follows:
     
    College Park Auto Parts: Store Items
     
    Control Text Name Other Properties
    DataGridView   dgvStoreItems Anchor: Top, Bottom, Left, Right
    ColumnHeadersHeightSizeMode: EnableResizing
    DataSource: dsStoreItems
    DataMember: AutoPart
    Button New Make... btnNewMake Anchor: Bottom, Left
    Button New Model... btnNewModel Anchor: Bottom, Left
    Button New Category... btnNewCategory Anchor: Bottom, Left
    Button Close btnClose Anchor: Bottom, Right
  76. Double-click the New Make button and implement the event as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    
    namespace CollegeParkAutoParts2
    {
        public partial class AutoParts : Form
        {
            public AutoParts()
            {
                InitializeComponent();
            }
    
            private void btnNewMake_Click(object sender, EventArgs e)
            {
                Makes vehicles = new Makes();
                vehicles.ShowDialog();
            }
        }
    }
    
  77. Return to the Part Editor dialog box and double-click the New Model button
  78. Implement the event as follows:
    private void btnNewModel_Click(object sender, EventArgs e)
    {
        Models vehicles = new Models();
        vehicles.ShowDialog();
    }
  79. Return to the Part Editor dialog box and double-click the New Category button
  80. Implement the event as follows:
    private void btnNewCategory_Click(object sender, EventArgs e)
    {
        ItemsCategories frmCategories = new ItemsCategories();
        frmCategories.ShowDialog();
    }
  81. Display the College Park Auto-Parts form and double-click the New Auto Part button
  82. Implement its event as follows:
    internal void ShowAutoParts()
    {
    }
    
    private void btnNewAutoPart_Click(object sender, EventArgs e)
    {
        AutoParts frmParts = new AutoParts();
                
        if (frmParts.ShowDialog() == DialogResult.Cancel)
            ShowAutoParts();
    }
  83. Execute the application to make sure everything is working well
     
    College Park Auto Parts
  84. Close the form(s) and return to your programming environment

The Rows of a Table

A record on a table is represented as a row (horizontal) of data. A row, or record, is an object based on the DataRow class.

To support the various records that belong to a table, the DataTable class is equipped with a property called Rows. The DataTable.Rows property is an object of the DataRowCollection class. The DataRowCollection class provides the necessary properties and methods you can use to create and manage the records of a table.

A record on a table is an object of type DataRow.

Creating a New Row

When performing data entry and while doing it on a record, the record has a status that can be identified by the DataRow.RowState property which is a value based on the DataRowState enumeration.

Before adding a new record to a table, you must let the table know. This is done by calling the DataTable.NewRow() method. Its syntax is:

public DataRow NewRow();

The DataTable.NewRow() method returns a DataRow object. Here is an example of calling it:

void InitializeComponent()
{
      DataRow rowStudent = tblRegistration.NewRow();
}

Data Entry

 

Introduction

When you call the DataTable.NewRow() method, the record's status is DataRowState.Detached.

After calling the DataTable.NewRow() method, you can specify the value that the column would carry. To do this, you must specify the table's column whose value you want to provide. You can locate a column based on an index as we mentioned already that the columns of a table are stored in the DataTable.Columns property which is based on the DataColumnCollection class. An example would be rowStudent["First Name"], which specifies the column named First Name. After specifying the column, assign it the desired but appropriate value. Here are examples of assigning values to the columns of a table:

void InitializeComponent()
{
    DataRow rowStudent = tblRegistration.NewRow();

    rowStudent["First Name"] = "Pauline";
    rowStudent["Last Name"]  = "Simms";
    rowStudent["Gender"]     = "Female";
}

Each column can also be identified by its index in the table. 

Adding a Record to a Table

After specifying the value(s) of the column(s), you must add it (them) to the table. To do this, you must call the Add() method of the DataRowCollection class. This method is overloaded with two versions. One of the versions uses the following syntax:

public void Add(DataRow row);

This method expects the name of the record as argument, which would be the value returned by a previous call to the DataTable.NewRow() method. Here is an example:

public class Exercise : Form
{
    DataGridView dgvStudents;

    DataSet dsRedOakHighSchool;
    DataTable tblRegistration;
    DataColumn colFirstName;
    DataColumn colLastName;
    DataColumn colGender;

    public Exercise()
    {
        InitializeComponent();
    }

    void InitializeComponent()
    {
        Text = "Students Records";
        dgvStudents = new DataGridView();
        dgvStudents.Location = new Point(12, 12);
        Controls.Add(dgvStudents);

        colFirstName = new DataColumn("First Name");
        colLastName = new DataColumn("Last Name");
        colGender = new DataColumn("Gender");

        tblRegistration = new DataTable("Student Registration");
        tblRegistration.Columns.Add(colFirstName);
        tblRegistration.Columns.Add(colLastName);
        tblRegistration.Columns.Add(colGender);

        dsRedOakHighSchool = new DataSet("Red Oak High School");
        dsRedOakHighSchool.Tables.Add(tblRegistration);

        DataRow rowStudent = tblRegistration.NewRow();
        rowStudent["First Name"] = "Pauline";
        rowStudent["Last Name"] = "Simms";
        rowStudent["Gender"] = "Female";

        tblRegistration.Rows.Add(rowStudent);

        dgvStudents.DataSource = dsRedOakHighSchool;
        dgvStudents.DataMember = "Student Registration";
    }
}

This would produce:

When the record has been added to the table, the record has a status of DataRowState.Added.

Adding an Array of Records

The above version of the DataRowCollection.Add() method means that you must identify each column before assigning a value to it. If you already know the sequence of columns and don't need to explicitly identify them, you can store all values in an array and simply add the array as a complete record. To support this, the DataRowCollection class provide another version of the .Add() method whose syntax is:

public virtual DataRow Add(object[] values);

Here is an example:

void InitializeComponent()
{
    . . . No Change

    DataRow rowStudent = tblRegistration.NewRow();
    rowStudent["First Name"] = "Pauline";
    rowStudent["Last Name"] = "Simms";
    rowStudent["Gender"] = "Female";
    tblRegistration.Rows.Add(rowStudent);

    object[] arrRecord = { "Edward", "Zaks", "Male" };
    tblRegistration.Rows.Add(arrRecord);

    dgvStudents.DataSource = dsRedOakHighSchool;
    dgvStudents.DataMember = "Student Registration";
}

This would produce:

There is an alternative to this second version of the DataRowCollection.Add() method. As opposed to passing an array of values to the Add() method, you can first define an array, assign that array to a DataRow variable, then pass that DataRow object to the Add() method. To support this technique, the DataRow class is equipped with an ItemArray property that expects an array. Here is an example

void InitializeComponent()
{
    Text = "Students Records";
    dgvStudents = new DataGridView();
    dgvStudents.Location = new Point(12, 12);
    Controls.Add(dgvStudents);

    colFirstName = new DataColumn("First Name");
    colLastName = new DataColumn("Last Name");
    colGender = new DataColumn("Gender");

    tblRegistration = new DataTable("Student Registration");
    tblRegistration.Columns.Add(colFirstName);
    tblRegistration.Columns.Add(colLastName);
    tblRegistration.Columns.Add(colGender);

    dsRedOakHighSchool = new DataSet("Red Oak High School");
    dsRedOakHighSchool.Tables.Add(tblRegistration);

    DataRow rowStudent = tblRegistration.NewRow();
    rowStudent["First Name"] = "Pauline";
    rowStudent["Last Name"] = "Simms";
    rowStudent["Gender"] = "Female";
    tblRegistration.Rows.Add(rowStudent);

    object[] arrRecord = { "Edward", "Zaks", "Male" };
    tblRegistration.Rows.Add(arrRecord);

    object[] arrStudent = { "Geraldine", "Rodetsky", "Unknown" };

    rowStudent = tblRegistration.NewRow();
    rowStudent.ItemArray = arrStudent;

    tblRegistration.Rows.Add(rowStudent);

    dgvStudents.DataSource = dsRedOakHighSchool;
    dgvStudents.DataMember = "Student Registration";
}

This would produce:

After creating the records of a table, if a record contains invalid values, the DataRow.HasErrors property can help you identify them.

The Number of Records of a Table

After you have created a table and its columns but before adding any row, the number of the table's records is set to 0. Every time you add a new record, the number of records is incremented by 1. To get the number of records that a table contains, access the Count property of its DataRowCollection collection.

Saving the Records of a Table

 

Introduction

When the application closes, unfortunately, all the information created while the application was running is lost. While the first goal of an application is to create one or more lists used to organize information, probably the essence of an information-based or a data-based application is to preserve information created when using the application and be able to retrieve that information the next time the application runs, without re-creating it.

Of course, there are various ways you can save the information created in an application. As the DataSet class is equipped with all the necessary features used to create and manage one or more lists of an application, it also provides a very high level of saving the information stored in its lists.

Saving a Data Set

Once a new record has been created or when the lists of the data set have been populated with information, you can save the changes and store them to a computer file. By default, the DataSet class is equipped to save its lists as XML. To support this, it is equipped with the WriteXml() method that is overloaded with various versions. One of the versions of this method uses the following syntax:

public void WriteXml(string fileName);

This method takes as argument the name of the new file or its path. When providing this argument, make sure you add the .xml extension to the file name. This method does two things: it checks the existence of the file and it saves it. If the file you provided is not found in the path, this method creates it and writes the record(s) to it. If the file exists already, this method opens it, finds its end, and appends the new data at the end. This makes the method very useful and friendly.

Here is an example of saving a data set using this method:

void InitializeComponent()
{
    . . . No Change

    tblRegistration.Rows.Add(rowStudent);

    dsRedOakHighSchool.WriteXml("students.xml");
}

If you want to control whether the file should be created from scratch, instead of passing the name of the file to this method, first create a stream using a Stream-derived class such as FileStream. This allows specifying the necessary options using the FileMode, FileAccess, and FileShare properties. Once the stream is ready, pass it to the WriteXml() method because it is also overloaded with the following syntax:

public void WriteXml(Stream stream);

Here is an example:

using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

public class Exercise : Form
{
    DataGridView dgvStudents;

    DataSet dsRedOakHighSchool;
    DataTable tblRegistration;
    DataColumn colFirstName;
    DataColumn colLastName;
    DataColumn colGender;

    public Exercise()
    {
        InitializeComponent();
    }

    void InitializeComponent()
    {
        Text = "Students Records";

        dgvStudents = new DataGridView();
        dgvStudents.Location = new Point(12, 12);
        Controls.Add(dgvStudents);

        colFirstName = new DataColumn("First Name");
        colLastName = new DataColumn("Last Name");
        colGender = new DataColumn("Gender");

        tblRegistration = new DataTable("Student Registration");
        tblRegistration.Columns.Add(colFirstName);
        tblRegistration.Columns.Add(colLastName);
        tblRegistration.Columns.Add(colGender);

        dsRedOakHighSchool = new DataSet("Red Oak High School");
        dsRedOakHighSchool.Tables.Add(tblRegistration);

        DataRow rowStudent = tblRegistration.NewRow();
        rowStudent["First Name"] = "Pauline";
        rowStudent["Last Name"] = "Simms";
        rowStudent["Gender"] = "Female";
        tblRegistration.Rows.Add(rowStudent);

        object[] arrRecord = { "Edward", "Zaks", "Male" };
        tblRegistration.Rows.Add(arrRecord);

        object[] arrStudent = { "Geraldine", "Rodetsky", "Unknown" };

        rowStudent = tblRegistration.NewRow();
        rowStudent.ItemArray = arrStudent;

        tblRegistration.Rows.Add(rowStudent);

        FileStream stmStudents = new FileStream("Registration.xml",
                                                 FileMode.Create,
                                                 FileAccess.Write);
        dsRedOakHighSchool.WriteXml(stmStudents);
    }
}

public class Program
{
    static int Main()
    {
        System.Windows.Forms.Application.Run(new Exercise());
        return 0;
    }
}

If you want the file to be formatted as text, you can use the following version of the method:

public void WriteXml(TextWriter writer);

If you prefer to use an XmlWriter variable to manage the file, use the following version of the method:

public void WriteXml(XmlWriter writer);

Obviously to use this method, you must first define an XmlWriter type of variable.

Practical LearningPractical Learning: Saving the Records of a Data Set

  1. Display the ItemsCategories form and double-click the Close button
  2. Implement the event as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    
    namespace CollegeParkAutoParts2
    {
        public partial class ItemsCategories : Form
        {
            public ListOfCategories()
            {
                InitializeComponent();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                dsCategories.WriteXml(@"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Categories.xml");
                Close();
            }
        }
    }
  3. Display the Makes form and double-click the Close button
  4. Implement the event as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    
    namespace CollegeParkAutoParts2
    {
        public partial class Makes : Form
        {
            public ListOfMakes()
            {
                InitializeComponent();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                dsMakes.WriteXml(@"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Makes.xml");
                Close();
            }
        }
    }
  5. Display the Models form and double-click the Close button
  6. Implement the event as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    
    namespace CollegeParkAutoParts2
    {
        public partial class Models : Form
        {
            public ListOfModels()
            {
                InitializeComponent();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                string strDirectory = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts";
    
                dsModels.WriteXml(strDirectory + "\\Models.xml");
                Close();
            }
        }
    }
  7. Display the Auto Parts form and double-click the Close button
  8. Implement its event as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        dsStoreItems.WriteXml(@"C:\Microsoft Visual C# Application Design\College Park Auto Parts\StoreItems.xml");
        Close();
    }
  9. Save all

Reading the XML Records of a Data Set

To open the data saved from a list, the DataSet class provides the ReadXml() method that is overloaded with various versions. One of the versions of this method uses the following syntax:

public XmlReadMode ReadXml(string fileName);

This method takes as argument the name of an existing XML file or its path. The method opens the file and provides the XML formatting as it was done when the file was saved. Here is an example of calling this method:

using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

public class Exercise : Form
{
    DataGridView dgvStudents;

    DataSet dsRedOakHighSchool;
    DataTable tblRegistration;
    DataColumn colFirstName;
    DataColumn colLastName;
    DataColumn colGender;

    public Exercise()
    {
        InitializeComponent();
    }

    void InitializeComponent()
    {
        Text = "Students Records";

        dgvStudents = new DataGridView();
        dgvStudents.Location = new Point(12, 12);
        Controls.Add(dgvStudents);

        colFirstName = new DataColumn("First Name");
        colLastName = new DataColumn("Last Name");
        colGender = new DataColumn("Gender");

        tblRegistration = new DataTable("Student Registration");
        tblRegistration.Columns.Add(colFirstName);
        tblRegistration.Columns.Add(colLastName);
        tblRegistration.Columns.Add(colGender);

        dsRedOakHighSchool = new DataSet("Red Oak High School");
        dsRedOakHighSchool.Tables.Add(tblRegistration);

        if( File.Exists("students.xml") )
        {
            dsRedOakHighSchool.ReadXml("students.xml");
            dgvStudents.DataSource = dsRedOakHighSchool;
            dgvStudents.DataMember = "Student Registration";
        }
    }
}

public class Program
{
    static int Main()
    {
        System.Windows.Forms.Application.Run(new Exercise());
        return 0;
    }
}

Although this method can read any XML file, if you use it to open a file that was saved by someone else or another application and you want to use it in your application, you should be familiar with the names of its nodes. If it contains names that are not "registered" or recognized by your DataSet object, the lists that compose your application may not be able to read it, not because the list was not formatted right, but because the lists of your application would be holding different names.

If the file was saved using a Stream-based class, you can pass a stream to the method based on the following syntax:

public XmlReadMode ReadXml(Stream stream);

In the same way, the method provides an equivalent version for the TextWriter and the XmlWriter versions:

public XmlReadMode ReadXml(TextReader reader);
public XmlReadMode ReadXml(XmlReader reader);

To use one of these versions, you must first define a TextWriter or an XmlReader type of variable.

When retrieving the content of the XML file, if you want it delivered as text, call the DataSet.GetXml() method. Its syntax is:

public string GetXml();

As you can see, this method returns a string.

Once a file has been opened, you can explore its content. The most obvious operation related to opening a data set consists of viewing its records.

Practical LearningPractical Learning: Opening the Records for a Data Set

  1. Display the ItemsCategories form and double-click an unoccupied area of its body
  2. Implement the event as follows:
    private void ItemsCategories_Load(object sender, EventArgs e)
    {
        string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Categories.xml";
    
        if( File.Exists(strFileName) )
            dsCategories.ReadXml(strFileName);
    }
  3. Display the Makes form and double-click an unoccupied area of its body
  4. Implement the event as follows:
    private void Makes_Load(object sender, EventArgs e)
    {
        string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Makes.xml";
    
        if( File.Exists(strFileName) )
            dsMakes.ReadXml(strFileName);
    }
  5. Display the Models form and double-click an unoccupied area of its body
  6. Implement the event as follows:
    private void CarModels_Load(object sender, EventArgs e)
    {
        string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Makes.xml";
    
        if( File.Exists(strFileName) )
            dsMakes.ReadXml(strFileName); 
                
        strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Models.xml";
        if( File.Exists(strFileName) )
            dsModels.ReadXml(strFileName);
    }
  7. Display the AutoParts form and double-click an unoccupied area of its body
  8. Implement the event as follows:
    private void AutoParts_Load(object sender, EventArgs e)
    {
        string Filename = @"C:\College Park Auto Parts\StoreItems.xml";
    
        if( File.Exists(Filename) )
            dsStoreItems.ReadXml(strFileName);
    }
  9. Return to the Auto-Parts form and, in the Properties window, click the Events button
  10. In the Events section of the Properties window, double-click Activated and implement the event as follows:
    private void AutoParts_Activated(object sender, EventArgs e)
    {
        string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Makes.xml";
                
        if( File.Exists(strFileName) )
            dsMakes.ReadXml(strFileName);
    
        strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Models.xml";
    
        if( File.Exists(strFileName) )
            dsModels.ReadXml(strFileName);
    
        strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Categories.xml";
    
        if( File.Exists(strFileName) )
            dsCategories.ReadXml(strFileName);
    }

Committing or Rejecting Changes to a List

When a user has created a record, the data set that holds the information is considered to have been modified because, obviously, it does not have the same information or the same records it had when the application was launched. You, as the programmer, have the option of accepting the changes or rejecting them. To accept the changes, call the DataSet.AcceptChanges() method. Its syntax is:

public void AcceptChanges();

If you don't want the changes to take effect, you can reject them by calling the DataSet.RejectChanges() method. Its syntax is:

public virtual void RejectChanges();

This method can be called to dismiss whatever changes were made on the records of the list(s).

 
 
 

Locating Records and Their Values

 

Locating a Record

Consider the following data set:

using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

public class Exercise : Form
{
    ListView lvwStudents;

    DataSet dsRedOakHighSchool;
    DataTable tblRegistration;
    DataColumn colStudentNumber;
    DataColumn colFirstName;
    DataColumn colLastName;
    DataColumn colGender;

    public Exercise()
    {
        InitializeComponent();
    }

    void InitializeComponent()
    {
        Text = "Students Records";

        lvwStudents = new ListView();
        lvwStudents.Location = new Point(12, 12);
        Controls.Add(lvwStudents);

        colStudentNumber = new DataColumn("StudentNumber");
        colFirstName = new DataColumn("FirstName");
        colLastName = new DataColumn("LastName");
        colGender = new DataColumn("Gender");

        tblRegistration = new DataTable("Student");
        tblRegistration.Columns.Add(colStudentNumber);
        tblRegistration.Columns.Add(colFirstName);
        tblRegistration.Columns.Add(colLastName);
        tblRegistration.Columns.Add(colGender);

        dsRedOakHighSchool = new DataSet("SchoolRecords");
        dsRedOakHighSchool.Tables.Add(tblRegistration);

        object[] objStudents1 = { "920759", "Pauline", "Simms", "Female" };
        tblRegistration.Rows.Add(objStudents1);
        object[] objStudents2 = { "281174", "Geraldine", "Rodetsky", "Unknown" };
        tblRegistration.Rows.Add(objStudents2);
        object[] objStudents3 = { "400795", "Edward", "Zaks", "Male" };
        tblRegistration.Rows.Add(objStudents3);
        object[] objStudents4 = { "931579", "Jeannete", "Palau", "Female" };
        tblRegistration.Rows.Add(objStudents4);
        object[] objStudents5 = { "315825", "Kate", "Hooks", "Unknown" };
        tblRegistration.Rows.Add(objStudents5);
        dsRedOakHighSchool.WriteXml("students.xml");
    }
}

public class Program
{
    static int Main()
    {
        System.Windows.Forms.Application.Run(new Exercise());
        return 0;
    }
}

This would produce:

<?xml version="1.0" standalone="yes"?>
<SchoolRecords>
  <Student>
    <StudentNumber>920759</StudentNumber>
    <FirstName>Pauline</FirstName>
    <LastName>Simms</LastName>
    <Gender>Female</Gender>
  </Student>
  <Student>
    <StudentNumber>281174</StudentNumber>
    <FirstName>Geraldine</FirstName>
    <LastName>Rodetsky</LastName>
    <Gender>Unknown</Gender>
  </Student>
  <Student>
    <StudentNumber>400795</StudentNumber>
    <FirstName>Edward</FirstName>
    <LastName>Zaks</LastName>
    <Gender>Male</Gender>
  </Student>
  <Student>
    <StudentNumber>931579</StudentNumber>
    <FirstName>Jeannete</FirstName>
    <LastName>Palau</LastName>
    <Gender>Female</Gender>
  </Student>
  <Student>
    <StudentNumber>315825</StudentNumber>
    <FirstName>Kate</FirstName>
    <LastName>Hooks</LastName>
    <Gender>Unknown</Gender>
  </Student>
</SchoolRecords>

Before performing any operation on a record, you must be able to locate it. That is, you must be able to identify a record among the various records of a table. The records of a table are stored in a list based on the DataRowCollection class. To locate a record in the DataTable.Rows collection, the DataRowCollection class has an indexed property that is defined as follows:

public DataRow this[int index] {get;}

The first record has an index of 0. The second record has an index of 1, and so on. Here is an example of identifying each column:

void InitializeComponent()
{
    Text = "Students Records";
    Size = new Size(320, 160);

    lvwStudents = new ListView();
    lvwStudents.Location = new Point(12, 12);
    lvwStudents.Size = new Size(290, 110);
    lvwStudents.View = View.Details;
    lvwStudents.GridLines = true;
    lvwStudents.FullRowSelect = true;

    Controls.Add(lvwStudents);

    colStudentNumber = new DataColumn("StudentNumber");
    colFirstName = new DataColumn("FirstName");
    colLastName = new DataColumn("LastName");
    colGender = new DataColumn("Gender");

    tblRegistration = new DataTable("Student");
    tblRegistration.Columns.Add(colStudentNumber);
    tblRegistration.Columns.Add(colFirstName);
    tblRegistration.Columns.Add(colLastName);
    tblRegistration.Columns.Add(colGender);

    dsRedOakHighSchool = new DataSet("SchoolRecords");
    dsRedOakHighSchool.Tables.Add(tblRegistration);

    dsRedOakHighSchool.ReadXml("students.xml");

    lvwStudents.Columns.Add("Student #");
    lvwStudents.Columns.Add("First Name", 75);
    lvwStudents.Columns.Add("Last Name", 75);
    lvwStudents.Columns.Add("Gender");

    for (int i = 0; i < tblRegistration.Rows.Count; i++)
    {
        DataRow rowStudent = tblRegistration.Rows[i];
    }
}

Each record of a table is an object of type DataRow. When you access a record, the compiler would check whether the record exists. If a record with that index exists, its DataRow value is produced.

Locating a Value by a Column's Index

Once you have located a record, you can find a particular value you are interested in, and you have tremendous options. Here is an example where the user had located and clicked the value "Paulson" in a record:

Locating a Value

Consider the following table of records:

To locate a value in a data set, you need two pieces of information: the record and the column. We have seen how to located a record. Each value of a table is created under a particular column. Therefore, you must be able to specify the column under which the value exists. To identify the columns of a table, the DataRow class is equipped with the overloaded indexed property which comes in 6 versions.

As seen in previous lessons, the columns of a table are indexed with the first column at 0, the second at 1, and so on. To allow you to identify a column by its index, one of the versions of the DataRow's indexed property uses the following syntax:

public object this[int columnIndex] {get; set;}

This property expects the index of the column. Here are examples:

void InitializeComponent()
{
    . . . No Change

    for (int i = 0; i < tblRegistration.Rows.Count; i++)
    {
        DataRow rowStudent = tblRegistration.Rows[i];

        ListViewItem lviStudent =
		new ListViewItem(rowStudent[0].ToString());
        lviStudent.SubItems.Add(rowStudent[1].ToString());
        lviStudent.SubItems.Add(rowStudent[2].ToString());
        lviStudent.SubItems.Add(rowStudent[3].ToString());

        lvwStudents.Items.Add(lviStudent);
    }
}

To access a record directly without first declaring a DataRow variable, the above code can also be written as follows:

void InitializeComponent()
{
    . . . No Change

    for (int i = 0; i < tblRegistration.Rows.Count; i++)
    {
        ListViewItem lviStudent =
		new ListViewItem(tblRegistration.Rows[i][0].ToString());
        lviStudent.SubItems.Add(tblRegistration.Rows[i][1].ToString());
        lviStudent.SubItems.Add(tblRegistration.Rows[i][2].ToString());
        lviStudent.SubItems.Add(tblRegistration.Rows[i][3].ToString());

        lvwStudents.Items.Add(lviStudent);
    }
}

You can use a foreach loop to visit the members of a DataColumnCollection collection. Like the DataColumnCollection class, the DataRowCollection class implements the GetEnumerator() method of the IEnumerable interface. This means that you can use the foreach loop on a collection of records to visit each member. Here is an example:

void InitializeComponent()
{
    . . . No Change

    foreach(DataRow rowStudent in tblRegistration.Rows)
    {
        ListViewItem lviStudent =
        	new ListViewItem(rowStudent[0].ToString());
        lviStudent.SubItems.Add(rowStudent[1].ToString());
        lviStudent.SubItems.Add(rowStudent[2].ToString());
        lviStudent.SubItems.Add(rowStudent[3].ToString());

        lvwStudents.Items.Add(lviStudent);
    }
}

Locating a Value by the Column Object Name

Instead of using the index of a column, you can locate a value using the object name of its column. To do this, you can use the following syntax of the DataRow indexed property:

public object this[string ColumnName] {get; set;}

This property expects the object name of the column passed in its square brackets. Here are examples:

void InitializeComponent()
{
    . . . No Change

    for (int i = 0; i < tblRegistration.Rows.Count; i++)
    {
        DataRow rowStudent = tblRegistration.Rows[i];

        ListViewItem lviStudent =
	    new ListViewItem(rowStudent["StudentNumber"].ToString());
        lviStudent.SubItems.Add(rowStudent["FirstName"].ToString());
        lviStudent.SubItems.Add(rowStudent["LastName"].ToString());
        lviStudent.SubItems.Add(rowStudent["Gender"].ToString());

        lvwStudents.Items.Add(lviStudent);
    }
}

Locating a Value by the Column Variable Name

Instead of using the index or the object name of a column, you can also locate a value using the variable name of its column. To do this, you can use the following syntax of the DataRow indexed property:

public object this[DataColumn column] {get; set;}

This property expects the object name of the column passed in its square brackets. Here are examples:

void InitializeComponent()
{
    . . . No Change

    for (int i = 0; i < tblRegistration.Rows.Count; i++)
    {
        DataRow rowStudent = tblRegistration.Rows[i];

        ListViewItem lviStudent =
		new ListViewItem(rowStudent[colStudentNumber].ToString());
        lviStudent.SubItems.Add(rowStudent[colFirstName].ToString());
        lviStudent.SubItems.Add(rowStudent[colLastName].ToString());
        lviStudent.SubItems.Add(rowStudent[colGender].ToString());

        lvwStudents.Items.Add(lviStudent);
    }
}

Locating a Value From the Column Collection

As mentioned already, to access a record, you can pass its index to the indexed property of the DataRowCollection, which produces a DataRow object. Using these concepts, you can access the values of a table. Here is an example:

void InitializeComponent()
{
    . . . No Change

    foreach(DataRow rowStudent in tblRegistration.Rows)
    {
        foreach (DataColumn col in tblRegistration.Columns)
        {
            MessageBox.Show(rowStudent[col].ToString());
        }
        break;
    }
}

This code allows you to access a record using a row of a table and to locate a value based on the name of its column, but the above code does not allow you to clearly identify the column whose value you want to access. To clearly locate a value, you should name its column and to do this, you can pass the column name to the indexed property of the record. Here are examples:

void InitializeComponent()
{
    . . . No Change

    foreach (DataRow rowStudent in tblRegistration.Rows)
    {
        foreach (DataColumn col in tblRegistration.Columns)
        {
            ListViewItem lviStudent =
                new ListViewItem(rowStudent["StudentNumber"].ToString());
            lviStudent.SubItems.Add(rowStudent["FirstName"].ToString());
            lviStudent.SubItems.Add(rowStudent["LastName"].ToString());
            lviStudent.SubItems.Add(rowStudent["Gender"].ToString());

            lvwStudents.Items.Add(lviStudent);
            break;
        }
    }
}

When using any of these previous techniques (whether using for or foreach), if you specify an index that is either less than 0 or beyond the number of records in the table, the compiler would throw an IndexOutOfRangeException exception.

Practical LearningPractical Learning: Getting the Values of a Data Set

  1. In the Solution Explorer, Double-click CollegeParkAutoParts.cs
  2. From the Data section of the Toolbox, click DataSet and click the form
  3. In the Add Dataset dialog box, click the Untyped dataset radio button and click OK
  4. In the Properties window, change the characteristics of the data set as follows:
    DataSetName: StoreItems
    (Name): dsStoreItems
  5. Click Tables and click its ellipsis button
  6. In the Properties list, change the characteristics of the table as follows:
    TableName: AutoPart
    (Name): tblStoreItem
  7. Click Columns and click its ellipsis button
  8. In the Columns Collection Editor, click Add continuously and create the columns as follows:
     
    ColumnName (Name)
    PartNumber colPartNumber
    Year colYear
    Make colMake
    Model colModel
    Category colCategory
    PartName colPartName
    UnitPrice colUnitPrice
  9. Click Close and click Close
  10. Right-click the form and click View Code
  11. Change the ShowAutoParts method as follows:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.Xml;
    
    namespace CollegeParkAutoParts2
    {
        public partial class CollegeParkAutoParts : Form
        {
            public CollegeParkAutoParts()
            {
                InitializeComponent();
            }
    
            internal void ShowAutoParts()
            {
                tvwAutoParts.Nodes.Clear();
                TreeNode nodRoot = tvwAutoParts.Nodes.Add("College Park Auto-Parts",
                                                          "College Park Auto-Parts", 0, 1);
                // Show the years nodes
                for (int years = DateTime.Today.Year + 1; years >= 1960; years--)
                    nodRoot.Nodes.Add(years.ToString(), years.ToString(), 2, 3);
    
                tvwAutoParts.SelectedNode = nodRoot;
                // Expand the root node
                tvwAutoParts.ExpandAll();
    
                // This is the file that holds the list of store items on sale
                string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\StoreItems.xml";
    
                if (File.Exists(strFileName))
                {
                    dsStoreItems.ReadXml(strFileName);
    
                    // Add the makes to the years
                    foreach (TreeNode nodYear in nodRoot.Nodes)
                    {
                        List<string> lstMakes = new List<string>();
    
                        foreach (DataRow row in tblStoreItem.Rows)
                        {
                            if (nodYear.Text == row["Year"].ToString())
                            {
                                if (!lstMakes.Contains(row["Make"].ToString()))
                                    lstMakes.Add(row["Make"].ToString());
                            }
                        }
    
                        foreach (string strMake in lstMakes)
                            nodYear.Nodes.Add(strMake, strMake, 4, 5);
                    }
    
                    // Add the models to the makes
                    foreach (TreeNode nodYear in nodRoot.Nodes)
                    {
                        foreach (TreeNode nodMake in nodYear.Nodes)
                        {
                            List<string> lstModels = new List<string>();
    
                            foreach (DataRow row in tblStoreItem.Rows)
                            {
                                if ((nodYear.Text == row["Year"].ToString()) &&
                                    (nodMake.Text == row["Make"].ToString()))
                                {
                                    if (!lstModels.Contains(row["Model"].ToString()))
                                        lstModels.Add(row["Model"].ToString());
                                }
                            }
    
                            foreach (string strModel in lstModels)
                                nodMake.Nodes.Add(strModel, strModel, 6, 7);
                        }
                    }
    
                    // Show the categories nodes
                    foreach (TreeNode nodYear in nodRoot.Nodes)
                    {
                        foreach (TreeNode nodMake in nodYear.Nodes)
                        {
                            foreach (TreeNode nodModel in nodMake.Nodes)
                            {
                                List<string> lstCategories = new List<string>();
    
                                foreach (DataRow row in tblStoreItem.Rows)
                                {
                                    if ((nodYear.Text == row["Year"].ToString()) &&
                                        (nodMake.Text == row["Make"].ToString()) &&
                                        (nodModel.Text == row["Model"].ToString()))
                                    {
                                        if (!lstCategories.Contains(row["Category"].ToString()))
                                            lstCategories.Add(row["Category"].ToString());
                                    }
                                }
    
                                foreach (string strCategory in lstCategories)
                                    nodModel.Nodes.Add(strCategory, strCategory, 8, 9);
                            }
                        }
                    }
                }
            }
        }
    }
  12. Return to the College Park Auto-Parts form and click the Part # text box
  13. In the Events section of the Properties window, double-click Leave and implement the event as follows:
    private void txtPartNumber_Leave(object sender, EventArgs e)
    {
        foreach (DataRow row in tblStoreItem.Rows)
        {
            if (row["PartNumber"].ToString() == txtPartNumber.Text)
            {
                txtPartName.Text = row["PartName"].ToString();
                txtUnitPrice.Text = row["UnitPrice"].ToString();
                txtQuantity.Text = "0";
                txtSubTotal.Text = "0.00";
            }
        }
    }
  14. Return to the College Park Auto-Parts form and double-click the Add/Select button
  15. Implement the event as follows:
    private void btnAdd_Click(object sender, EventArgs e)
    {
        if (txtPartNumber.Text.Length == 0)
        {
            MessageBox.Show("There is no part to be added to the order.",
                            "College Park Auto-Parts",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
            return;
        }
    
        ListViewItem lviSelectedPart =
                    new ListViewItem(txtPartNumber.Text);
    
        lviSelectedPart.SubItems.Add(txtPartName.Text);
        lviSelectedPart.SubItems.Add(txtUnitPrice.Text);
        lviSelectedPart.SubItems.Add(txtQuantity.Text);
        lviSelectedPart.SubItems.Add(txtSubTotal.Text);
        lvwSelectedParts.Items.Add(lviSelectedPart);
    
        CalculateOrder();
    }
  16. Return to the College Park Auto-Parts form and double-click the New Customer Order button
  17. Implement the event as follows:
    private void btnNewCustomerOrder_Click(object sender, EventArgs e)
    {
        int ReceiptNumber = 0;
        string Filename = @"C:\College Park Auto Parts\receipts.xml";
        XmlDocument DOMReceipts = new XmlDocument();
    
        if( File.Exists(strFileName) )
        {
            DOMReceipts.Load(Filename);
            XmlElement RootReceipts = DOMReceipts.DocumentElement;
    
            XmlNodeList ListOfReceiptNumbers =
    		RootReceipts.GetElementsByTagName("ReceiptNumber");
            ReceiptNumber = int.Parse(ListOfReceiptNumbers[
    		ListOfReceiptNumbers.Count - 1].InnerText);
        }
    
        txtSave.Text = (ReceiptNumber + 1).ToString();
        txtTaxRate.Text = "5.75";
        txtTaxAmount.Text = "0.00";
        txtPartsTotal.Text = "0.00";
        txtOrderTotal.Text = "0.00";
        lvwSelectedParts.Items.Clear();
    }
  18. Return to the College Park Auto-Parts form and click the tree view
  19. In the Properties window, click the Events button and, in the Events section, double-click NodeMouseClick
  20. Implement the event as follows:
    private void tvwAutoParts_NodeMouseClick(object sender,
    		TreeNodeMouseClickEventArgs e)
    {
        TreeNode tnClicked = e.Node;
    
        if (nodClicked.Level == 4)
            lvwAutoParts.Items.Clear();
    
        try
        {
            foreach (DataRow row in tblStoreItem.Rows)
            {
                if ((row["Category"].ToString() == tnClicked.Text) &&
                    (row["Model"].ToString()    == tnClicked.Parent.Text) &&
                    (row["Make"].ToString()     == tnClicked.Parent.Parent.Text) &&
                    (row["Year"].ToString()     == tnClicked.Parent.Parent.Parent.Text))
                {
                    ListViewItem lviAutoPart =
                        new ListViewItem(row["PartNumber"].ToString());
    
                    lviAutoPart.SubItems.Add(row["PartName"].ToString());
                    lviAutoPart.SubItems.Add(row["UnitPrice"].ToString());
                    lvwAutoParts.Items.Add(lviAutoPart);
                }
            }
        }
        catch (NullReferenceException)
        {
        }
    }
  21. Return to the College Park Auto-Parts form and double-click the Save button
  22. Implement its event as follows:
    private void btnSave_Click(object sender, EventArgs e)
    {
        // This is the file that holds the receipts
        string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Receipts.xml";
        // Get a reference to the root
        XmlDocument xdReceipts = new XmlDocument();
    
        // We will create a list of all the parts 
        // that the customer wants to purchase
        string strParts = "";
    
        foreach (ListViewItem lviPart in lvwSelectedParts.Items)
        {
            strParts = strParts + "<Part>";
            strParts = strParts + "<PartNumber>" + lviPart.SubItems[0].Text + "</PartNumber>";
            strParts = strParts + "<PartName>" + lviPart.SubItems[1].Text + "</PartName>";
            strParts = strParts + "<UnitPrice>" + lviPart.SubItems[2].Text + "</UnitPrice>";
            strParts = strParts + "<Quantity>" + lviPart.SubItems[3].Text + "</Quantity>";
            strParts = strParts + "<SubTotal>" + lviPart.SubItems[4].Text + "</SubTotal>";
            strParts = strParts + "</Part>";
        }
    
        // If this is the first customer order, ...
        if (!File.Exists(strFileName))
        {
            // If this is the first receipt to be created,
            // set the receipt number to 1
            // and create the structure of the document
            xdReceipts.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                "<CustomersOrders>" +
                                "<Receipt>" +
                                "<ReceiptNumber>1</ReceiptNumber>" + strParts +
                                "<PartsTotal>" + txtPartsTotal.Text +
                                "</PartsTotal><TaxRate>" + txtTaxRate.Text +
                                "</TaxRate><TaxAmount>" + txtTaxAmount.Text +
                                "</TaxAmount><OrderTotal>" + txtOrderTotal.Text +
                                "</OrderTotal></Receipt></CustomersOrders>");
    
            // Save the XML file
            xdReceipts.Save(strFileName);
    
            // Reset the customer order
            txtSave.Text = "2";
            txtOpen.Text = "1";
            txtTaxRate.Text = "5.75";
            txtTaxAmount.Text = "0.00";
            txtPartsTotal.Text = "0.00";
            txtOrderTotal.Text = "0.00";
            lvwSelectedParts.Items.Clear();
        } // If this is not the first customer order, ...
        else // if (File.Exists(Filename))
        {
            XmlNode xnCustomerOrder = null;
            // We will use a receipt number for each receipt
            int iReceiptNumber = int.Parse(txtSave.Text);
    
            // If at least one receipt had previously been created,
            // then open the XML file that holds the receipts
    
            // Store the XML file structure into the DOM
            xdReceipts.Load(strFileName);
            // Get a reference to the root element
            XmlElement xeCustomersOrders = xdReceipts.DocumentElement;
    
            // Get a list of the receipt numbers
            XmlNodeList xnlListOfReceipts = xeCustomersOrders.GetElementsByTagName("Receipt");
    
            // Check each receipt
            foreach (XmlNode xnCurrentReceipt in xnlListOfReceipts)
            {
                // Look for a receipt that has the same number
                // as in the Save text box
                if (xnCurrentReceipt["ReceiptNumber"].InnerText == txtSave.Text)
                {
                    // If you find it, reserve it
                    xnCustomerOrder = xnCurrentReceipt;
                    break;
                }
            }
            // Locate the last receipt number
            iReceiptNumber = int.Parse(txtSave.Text);
    
            // Create an element named Receipt
            XmlElement xeReceipt = xdReceipts.CreateElement("Receipt");
            string strReceipt = "<ReceiptNumber>" + iReceiptNumber.ToString() +
                                "</ReceiptNumber>" + strParts +
                                "<PartsTotal>" + txtPartsTotal.Text +
                                "</PartsTotal><TaxRate>" + txtTaxRate.Text +
                                "</TaxRate><TaxAmount>" + txtTaxAmount.Text +
                                "</TaxAmount><OrderTotal>" + txtOrderTotal.Text +
                                "</OrderTotal>";
    
            // Create the XML code of the new element
            xeReceipt.InnerXml = strReceipt;
    
            // If this is a new customer order
            if (xnCustomerOrder == null)
            {
                // Add the new receipt to the file
                xdReceipts.DocumentElement.AppendChild(xeReceipt);
            } // If the customer order existed already, we will only update it
            else // if (NodeCustomerOrder != null)
            {
                // Replace the existing customer order with the current one
                xdReceipts.DocumentElement.ReplaceChild(xeReceipt, xnCustomerOrder);
            }
    
            // Save the XML file
            xdReceipts.Save(strFileName);
    
            // Reset the customer order
            btnNewCustomerOrder_Click(sender, e);
        }
    }
  23. Return to the College Park Auto-Parts form and double-click the Open button
  24. Implement its event as follows:
    private void btnOpen_Click(object sender, EventArgs e)
    {
        XmlDocument xdReceipts = new XmlDocument();
        string strFileName = @"C:\Microsoft Visual C# Application Design\College Park Auto Parts\Receipts.xml";
    
        // Check that the file exists. If so, open it
        if (File.Exists(strFileName))
        {
            // This variable will allow us to know if we have the receipt number
            bool found = false;
            // Empty the list of selected parts
            lvwSelectedParts.Items.Clear();
    
            // After opening the XML file, store it in the DOM
            xdReceipts.Load(strFileName);
    
            // Get a list of the receipts in the file
            XmlNodeList xnlListOfReceipts = xdReceipts.DocumentElement.GetElementsByTagName("Receipt");
    
            // Check each receipt
            foreach (XmlNode xnReceiptNumber in xnlListOfReceipts)
            {
                // Look for a receipt that has the same number
                // as on the Open text box
                if (xnReceiptNumber["ReceiptNumber"].InnerText == txtOpen.Text)
                {
                    // If you find it, make a note
                    found = true;
                    txtOpen.Text = xnReceiptNumber["ReceiptNumber"].InnerText;
                    txtSave.Text = xnReceiptNumber["ReceiptNumber"].InnerText;
    
                    // Retrieve the values of the receipt and display them on the form
                    try
                    {
                        foreach (XmlNode xnReceiptValues in xnReceiptNumber.ChildNodes)
                        {
                            XmlNode node = xnReceiptValues.NextSibling.ChildNodes[0];
    
                            ListViewItem lviReceipt = new ListViewItem(node.InnerText);
    
                            lviReceipt.SubItems.Add(node.NextSibling.InnerText);
                            lviReceipt.SubItems.Add(node.NextSibling.NextSibling.InnerText);
                            lviReceipt.SubItems.Add(node.NextSibling.NextSibling.NextSibling.InnerText);
                            lviReceipt.SubItems.Add(node.NextSibling.NextSibling.NextSibling.NextSibling.InnerText);
    
                            lvwSelectedParts.Items.Add(lviReceipt);
                        }
    
                        txtPartsTotal.Text = xnReceiptNumber["PartsTotal"].InnerText;
                        txtTaxRate.Text = xnReceiptNumber["TaxRate"].InnerText;
                        txtTaxAmount.Text = xnReceiptNumber["TaxAmount"].InnerText;
                        txtOrderTotal.Text = xnReceiptNumber["OrderTotal"].InnerText;
                    }
                    catch (NullReferenceException)
                    {
                    }
                }
            }
    
            // If the receipt was not found, let the user know
            if (found == false)
            {
                MessageBox.Show("There is no customer order with that receipt number.",
                                "College Park Auto-Parts",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);
                txtSave.Text = txtOpen.Text;
            }
        }// IF the XML file was not found, let the user know
        else
            MessageBox.Show("The file " + strFileName + " was not found.",
                            "College Park Auto-Parts",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
  25. Returo to the College Park Auto-Parts form and double-click an unoccupied area of its body
  26. Implement the Load event it as follows:
    private void CollegeParkAutoParts_Load(object sender, EventArgs e)
    {
        Directory.CreateDirectory(@"C:\Microsoft Visual C# Application Design\College Park Auto Parts");
        ShowAutoParts();
        btnNewCustomerOrder_Click(sender, e);
    }
  27. Return to the College Park Auto-Parts form and double-click the Close button
  28. Implement the event as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  29. Execute the application
  30. Click the New Auto Part button
  31. Click the New Make button
  32. Create a few makes as follows:
     
    Ford
    Dodge
    Toyota
    Honda
  33. Click the New Model button and create a few models as follows:
     
    Ford Escort SE L4 2.0
    Dodge Caravan SE L4 2.4
    Toyota Rav4 2WD/4-Door
    Honda Civic 1.7 EX 4DR
    Ford Taurus LX V6 3.0
    Honda Accord 2.3 LX 4DR
  34. Click the New Category button and create a few categories as follows:
     
    Exhaust
    Air Intake
    Fuel Injection
    Cooling System
    Engine Electrical
  35. Create a few parts 
  36. Close the Part Editor
  37. Create a few customer part orders and save them:
     
    College Park Auto Parts: Customer Order
     
    College Park Auto Parts: Part Selection
  38. Close the forms and return to your programming environment
  39. Execute the application again and open a previously saved order
  40. Close the forms and return to your programming environment

Exercises

 
 

College Park Auto Parts

 
  1. Open the CollegeParkAutoParts2 application from this lesson
  2. Create a Part Editor form and design it as follows:
     
  3. Add a context menu for the Available Parts list view with the items: Select, Edit..., and Delete
     
  4. Configure the context menu so that
    1. If the user clicks Select, the behavior would be the same as if the user had double-clicked the item
    2. If the user clicks Edit..., the Part Editor dialog box would display with the part in it. The user can then edit any part (year, make, model, category, part name, or unit price) except the part number. Then the user can save the changed part
    3. If the user clicks Delete, a message box would warn the user and ask for confirmation with Yes/No answers. If the user clicks Yes, the part would be deleted from the AutoParts list
  5. Configure the application so that the user can open an order, add new parts to it, or delete parts from it, then save the order
  6. Extend the application so that the store can also sell items that are, or are not, car-related, such as books, t-shirts, cleaning items, maintenance items (steering oils, brake oils, etc), license plates, etc. Every item in the store should have an item number. The user can enter that item number in the Part # text box and press Tab or Enter. The corresponding item would then be retrieved from the database and displayed on the form. If there is no item with that number, a message box should let the user know
 
 
   
 

Previous Copyright © 2005-2014, FunctionX Next