Home

List-Based Applications

 
Music Store

Tables Records

    

Introduction to Records

In our description of tables, we saw that a table was made of one or various columns that represent categories of data. After creating such a table and its columns that represent the categories, 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.

Data entry is performed by entering a value under the column headers. The group of values that correspond to the same entry or the same line under the columns is called a record. This also means that the records are entered one line, also called a row, at a time. Here is a table filled with various records:

A record on a table is represented as a row (horizontal) of data. 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 in fact an object of the DataRowCollection class. The DataRowCollection class provides the necessary properties and methods you can use to create and manage records of a table. A row itself is an object based on the DataRow class.

Practical Learning Practical Learning: Introducing Records

  1. Start Microsoft Visual Studio .NET and create a new Windows Forms Application named MusicStore2
  2. To add a new form, on the main menu, click Project -> Add New Item...
  3. In the Templates list, click Windows Forms (.NET)
  4. Set the Name to DataCenter and press Enter
  5. To add a new form, on the main menu, click Project -> Add New Item...
  6. In the Templates list of the Add New Item dialog box, click Windows Forms (.NET)
  7. Set the Name to Categories and press Enter
  8. Design the form as follows:
     
    Control Name Text Other Properties
    DataGrid     Auto Format: Professional 3
    Label   New Category:  
    TextBox txtNewCategory    
    Button btnAdd Add  
    Button btnClose Close  
    Form     AcceptButton: btnAdd
    CancelButton: btnClose
    FormBorderStyle: FixedDialog
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskbar: False
    StartPosition: CenterScreen
  9. To add a new form, on the main menu, click Project -> Add New Item...
  10. In the Templates list of the Add New Item dialog box, click Windows Forms (.NET)
  11. Set the Name to ItemTypes and press Enter
  12. Design the form as follows:
     
    Control Name Text Other Properties
    DataGrid     Auto Format: Professional 3
    Label   New Item Type:  
    TextBox txtNewItemType    
    Button btnAdd Add  
    Button btnClose Close  
    Form     AcceptButton: btnAdd
    CancelButton: btnClose
    FormBorderStyle: FixedDialog
    MaximizeBox: False
    MinimizeBox: False
    ShowInTaskbar: False
    StartPosition: CenterScreen
  13. To add a new form, on the main menu, click Project -> Add New Item...
  14. In the Templates list of the Add New Item dialog box, click Windows Forms (.NET)
  15. Set the Name to NewStoreItem and press Enter
  16. Design the form as follows:
     
    Control Name Text Other Properties
    Label   Category:  
    ComboBox cboCategories   DropDownStyle: DropDownList
    Sorted: True
    Button btnNewCategory New  
    Label   Item Type:  
    ComboBox cboItemTypes   DropDownStyle: DropDownList
    Sorted: True
    Button btnNewType New  
    Label   Item Name:  
    TextBox txtItemName    
    Label   Unit Price:  
    TextBox txtUnitPrice 0.00 AlignText: Right
    Label   Item #:  
    TextBox txtItemNumber    
    Button btnCreate Create  
    Button btnClose Close  
    Form     AcceptButton: btnCreate
    CancelButton: btnClose 
    MaximizeBox: False
    StartPosition: CenterScreen
  17. Double-click an unoccupied area of the form to access its Load event and implement its as follows:
     
    System::Void NewStoreItem_Load(System::Object *  sender, System::EventArgs *  e)
    {
    	 // We will generate a random number for the store item
    	 DateTime tmeNow = DateTime::Now;
    	 Random *rndNumber = new Random(tmeNow.Millisecond);
    	 String *strNumber = rndNumber->Next(100000, 999999).ToString();
    
    	 // Display the new number in the Part # text box
    	 this->txtItemNumber->Text = strNumber;
    
    	 // Disable the OK button to indicate that the item is not ready
    	 this->btnCreate->Enabled = false;
    }
  18. Return to the NewStoreItem form
  19. Double-click the top New button on the right side of the Category combo box
  20. Return to the NewStoreItem form and double-click the lower New button
  21. In the top section of the file, under the #pragma line, type:
     
    #include "Categories.h"
    #include "ItemTypes.h"
  22. Implement the Click events as follows:
     
    System::Void btnNewCategory_Click(System::Object *  sender, _
    		System::EventArgs *  e)
    {
    	 Categories *frmCat = new Categories;
    
    	 frmCat->ShowDialog();
    }
    
    System::Void btnNewType_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 ItemTypes *frmTypes = new ItemTypes;
    
    	 frmTypes->ShowDialog();
    }
  23. To add a new form, on the main menu, click Project -> Add New Item...
  24. In the Templates list of the Add New Item dialog box, click Windows Forms (.NET)
  25. Set the Name to PurchaseOrder and press Enter
  26. Design the form as follows:
     
    Control Name Text Other Properties
    GroupBox   Selection of Sale Item  
    Label   Category  
    Label   Types  
    Label   Available Items  
    Button btnNewItem New Item  
    ListBox lbxCategories    
    ListBox lbxItemTypes    
    ListBox lbxAvailableItems    
    GroupBox   Items Sold  
    Label   Item #  
    Label   Item Name  
    Label   Unit Price  
    Label   Qty  
    Label   Sub Total  
    TextBox txtItemNumber1    
    TextBox txtItemName1    
    TextBox txtUnitPrice1 0.00 AlignText: Right
    TextBox txtQuantity1 0 AlignText: Right
    TextBox txtSubTotal1 0.00 AlignText: Right
    TextBox txtItemNumber2    
    TextBox txtItemName2    
    TextBox txtUnitPrice2 0.00 AlignText: Right
    TextBox txtQuantity2 0 AlignText: Right
    TextBox txtSubTotal2 0.00 AlignText: Right
    TextBox txtItemNumber3    
    TextBox txtItemName3    
    TextBox txtUnitPrice3 0.00 AlignText: Right
    TextBox txtQuantity3 0 AlignText: Right
    TextBox txtSubTotal3 0.00 AlignText: Right
    TextBox txtItemNumber4    
    TextBox txtItemName4    
    TextBox txtUnitPrice4 0.00 AlignText: Right
    TextBox txtQuantity4 0 AlignText: Right
    TextBox txtSubTotal4 0.00 AlignText: Right
    TextBox txtItemNumber5    
    TextBox txtItemName5    
    TextBox txtUnitPrice5 0.00 AlignText: Right
    TextBox txtQuantity5 0 AlignText: Right
    TextBox txtSubTotal5 0.00 AlignText: Right
    TextBox txtItemNumber6    
    TextBox txtItemName6    
    TextBox txtUnitPrice6 0.00 AlignText: Right
    TextBox txtQuantity6 0 AlignText: Right
    TextBox txtSubTotal6 0.00 AlignText: Right
    GroupBox   Order Processing  
    Button btnCalculate Calculate Order  
    Button btnClose Close  
    Label   Total Order:  
    TextBox txtTotalOrder 0.00 AlignText: Right
    Form     CancelButton: btnClose
    MaximizeBox: False
    StartPosition: CenterScreen
  27. Double-click the NewItem button
  28. In the top section of the file, under the #pragma line, type #include "NewStoreItem.h"
  29. Implement its Click event as follows:
     
    System::Void btnNewItem_Click(System::Object *  sender, System::EventArgs *  e)
    {	 
    	 NewStoreItem *frm = new NewStoreItem;
    	 frm->ShowDialog();
    }
  30. Double-click the Calculate Order button and implement its Click event as follows:
     
    System::Void btnCalculate_Click(System::Object *  sender, _
    		System::EventArgs *  e)
    {
     	double item1UnitPrice = 0.00, item2UnitPrice = 0.00, 
    		item3UnitPrice = 0.00, item4UnitPrice = 0.00, 
    		item5UnitPrice = 0.00, item6UnitPrice = 0.00;
    	 int quantity1 = 0, quantity2 = 0, quantity3 = 0,
    		 quantity4 = 0, quantity5 = 0, quantity6 = 0;
     	double item1SubTotal = 0.00, item2SubTotal = 0.00, 
    		item3SubTotal = 0.00, item4SubTotal = 0.00, 
    		item5SubTotal = 0.00, item6SubTotal = 0.00;
    	 double totalOrder;
    
    	 try {
    		 item1UnitPrice = this->txtUnitPrice1->Text->ToDouble(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Unit Price");
    		 this->txtUnitPrice1->Text = S"0.00";
    		 this->txtUnitPrice1->Focus();
    	 }
    
    	 try {
    		 quantity1 = this->txtQuantity1->Text->ToInt16(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Quantity");
    		 this->txtQuantity1->Text = S"0";
    		 this->txtQuantity1->Focus();
    	 }
    
    	 try {
    		 item2UnitPrice = this->txtUnitPrice2->Text->ToDouble(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Unit Price");
    		 this->txtUnitPrice2->Text = S"0.00";
    		 this->txtUnitPrice2->Focus();
    	 }
    
    	 try {
    		 quantity2 = this->txtQuantity2->Text->ToInt16(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Quantity");
    		 this->txtQuantity2->Text = S"0";
    		 this->txtQuantity2->Focus();
    	 }
    
    	 try {
    		 item3UnitPrice = this->txtUnitPrice3->Text->ToDouble(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Unit Price");
    		 this->txtUnitPrice3->Text = S"0.00";
    		 this->txtUnitPrice3->Focus();
    	 }
    
    	 try {
    		 quantity3 = this->txtQuantity3->Text->ToInt16(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Quantity");
    		 this->txtQuantity3->Text = S"0";
    		 this->txtQuantity3->Focus();
    	 }
    
    	 try {
    		 item4UnitPrice = this->txtUnitPrice4->Text->ToDouble(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Unit Price");
    		 this->txtUnitPrice4->Text = S"0.00";
    		 this->txtUnitPrice4->Focus();
    	 }
    
    	 try {
    		 quantity4 = this->txtQuantity4->Text->ToInt16(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Quantity");
    		 this->txtQuantity4->Text = S"0";
    		 this->txtQuantity4->Focus();
    	 }
    
    	 try {
    		 item5UnitPrice = this->txtUnitPrice5->Text->ToDouble(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Unit Price");
    		 this->txtUnitPrice5->Text = S"0.00";
    		 this->txtUnitPrice5->Focus();
    	 }
    
    	 try {
    		 quantity5 = this->txtQuantity5->Text->ToInt16(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Quantity");
    		 this->txtQuantity5->Text = S"0";
    		 this->txtQuantity5->Focus();
    	 }
    
    	 try {
    		 item6UnitPrice = this->txtUnitPrice6->Text->ToDouble(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Unit Price");
    		 this->txtUnitPrice6->Text = S"0.00";
    		 this->txtUnitPrice6->Focus();
    	 }
    
    	 try {
    		 quantity6 = this->txtQuantity6->Text->ToInt16(0);
    	 }
    	 catch(FormatException *)
    	 {
    		 MessageBox::Show(S"Invalid Quantity");
    		 this->txtQuantity6->Text = S"0";
    		 this->txtQuantity6->Focus();
    	 }
    
    	 item1SubTotal = item1UnitPrice * quantity1;
    	 item2SubTotal = item2UnitPrice * quantity2;
    	 item3SubTotal = item3UnitPrice * quantity3;
    	 item4SubTotal = item4UnitPrice * quantity4;
    	 item5SubTotal = item5UnitPrice * quantity5;
    	 item6SubTotal = item6UnitPrice * quantity6;
    
    	 totalOrder    = item1SubTotal + item2SubTotal + item3SubTotal +
    		             item4SubTotal + item5SubTotal + item6SubTotal;
    
    	 this->txtSubTotal1->Text = item1SubTotal.ToString(S"F");
    	 this->txtSubTotal2->Text = item2SubTotal.ToString(S"F");
    	 this->txtSubTotal3->Text = item3SubTotal.ToString(S"F");
    	 this->txtSubTotal4->Text = item4SubTotal.ToString(S"F");
    	 this->txtSubTotal5->Text = item5SubTotal.ToString(S"F");
    	 this->txtSubTotal6->Text = item6SubTotal.ToString(S"F");
    	 this->txtTotalOrder->Text = totalOrder.ToString(S"F");
    }
  31. Display the first form (Form1.h [Design]) and design it as follows:
     
    Control Name Text
    Button btnNewItem New Store Item
    Button btnNewOrder New Purchase Order
    Button btnClose Close
  32. Double-click the New Store Item button
  33. Return to the form and double-click the New Purchase Order and the Close buttons
  34. Implement the Click events as follows:
     
    #pragma once
    
    #include "NewStoreItem.h"
    #include "PurchaseOrder.h"
    
    namespace MusicStore2
    {
    	. . . No Change
    		
    	
    private: System::Void btnNewItem_Click(System::Object *  sender, _
    	System::EventArgs *  e)
    {
    	 NewStoreItem *frm = new NewStoreItem;
    	 frm->ShowDialog();
    }
    
    private: System::Void btnNewOrder_Click(System::Object *  sender, _
    	System::EventArgs *  e)
    {
    	 PurchaseOrder *frm = new PurchaseOrder;
    	 frm->ShowDialog();
    }
    
    private: System::Void btnClose_Click(System::Object *  sender, _
    	System::EventArgs *  e)
    {
    	 Close();
    }
    
    };
    }
  35. Save all

Performing Application Data Entry

 

Introduction

To allow the user to perform data entry, you must create an appropriate object meant for this task. You have various options. You can use various controls on the same view or provide a data sheet type of view such as the one available from the DataGrid control. In all cases, when the user performs data entry, by default, it is by entering one record at a time. Any time while the user is performing an operation on a record, the record has a status that can be identify by the DataRow::RowState property which is a value based on the DataRowState enumerator.

A record on a table is represented as a row of data. To support the various records that belong to a table, the DataTable class is equipped with the Rows property which is an object of type DataRowCollection with each record an object of type DataRow.

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:

System::Void btnNewDirector_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *rowDirector = this->dtDirectors->NewRow();
}

Practical Learning Practical Learning: Introducing Data Entry

  1. Display the DataCenter form (DataCenter.h [Design])
  2. In the Toolbox, click the Data button.
    To create a DataSet, click DataSet and click the DataModule form
     
  3. In the Add Dataset dialog box, click the Untyped Dataset radio button and click OK
  4. While the DataSet control is still selected, in the Properties window, click (Name) and type dsMusicStore
  5. Still in the Properties window, set the DataSetName to MusicStore
  6. Set its Modifiers property to Public so it can be easily accessed from other objects
  7. Under the DataCenter form, click dsMusicStore if necessary. In the Properties window, click the Tables field to reveal its ellipsis button ellipsis and click the ellipsis button ellipsis
  8. In the Tables Collection Editor, click the Add button
  9. Click (Name) and type tblCategories
  10. Click TableName and type Categories
  11. Set its Modifiers property to Public
  12. Click the Columns field to reveal its ellipsis button ellipsis and click its ellipsis button ellipsis
  13. In the Columns Collection Editor, click the Add button
  14. Change the (Name) to colCategory and change the ColumnName field to Category
  15. Set its Modifiers property to Public
  16. Click Close
  17. In the same way, create a table as
    (Name): tblItemTypes
    TableName: ItemTypes
  18. Add a column with the following properties:
    (Name): colItemType
    ColumnName: ItemType
    Modifiers: Public

     
  19. In the same way, create a table as
    (Name): tblAvailableItems
    TableName: AvailableItems
    Modifiers: Public
  20. Add the following columns to it
     
    (Name) ColumnName Modifiers
    colItemNumber ItemNumber Public
    colItemCategory Category Public
    colTypeOfItem ItemType Public
    colItemName ItemName Public
    colUnitPrice UnitPrice Public
  21. Click Close twice

Adding a Value Based on the Column Index

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. Each column can be identified by its index. Using this index, to assign a new value to the column, use the following version of the DataRow::Item property:

public: __property void set_Item(int* columnIndex);

Here is an example:

System::Void btnNewActor_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *rowActor = this->dtActors->NewRow();

	 rowActor->Item[0] = S"Martin Balsam";
}

When the record has been added to the table, the record has a status of DataRowState::Added. The above version of the DataRowCollection::Add() method allows you to add a value for one column. To complete a record, you would have to create a value for each column.

 

Practical Learning Practical Learning: Creating a Record From the Column Index

  1. Display the Categories form and double-click its Add button
  2. In the top section of the file, type
     
    #pragma once
    
    #include "DataCenter.h"
    
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
  3. Implement the event as follows:
     
    System::Void btnAdd_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the Data Center because 
    	 // that's where the DataSet object resides
    	 DataCenter *frmData = new DataCenter;
    
    	 // Create a new record for the Categories table
    	 DataRow *rowNewCategory = frmData->dsMusicStore->Tables->Item[S"Categories"]->NewRow();
    	 // Specify only the Category column since the CategoryID is auto-incrementing
    	 rowNewCategory->Item[0] = this->txtNewCategory->Text;
    	 // Add the new record to the Categories table
    	 frmData->dsMusicStore->Tables->Item[S"Categories"]->Rows->Add(rowNewCategory);
    
    	 // Display the current records of the Categories table so
    	 // the user would know what categories are already in the table
    	 this->dataGrid1->DataSource = frmData->dsMusicStore;
    	 this->dataGrid1->DataMember = S"Categories";
    
    	 // Reset the text box in case the user wants to add another category
    	 this->txtNewCategory->Text = S"";
    	 this->txtNewCategory->Focus();
    }
  4. Save the form

Adding a Value Based on the Column Variable Name

If you prefer to use the variable name of a column when adding the value, you can use the following version of the property:

public: __property void set_Item(DataColumn* name);

Here is an example of using this version of the property:

System::Void btnNewCategory_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *rowCategory = this->dtVideoCategories->NewRow();

	 rowCategory->Item[this->colCategory] = S"Documentary";			 
}

Practical Learning Practical Learning: Creating a Record From the Column Variable Name

  1. Display the ItemTypes form and double-click its Add button
  2. In the top section of the file, type
     
    #pragma once
    
    #include "DataCenter.h"
    
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
  3. Implement the event as follows:
     
    System::Void btnAdd_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 DataCenter *frmData = new DataCenter;
    
    	 DataRow *rowNewType = frmData->dsMusicStore->Tables->Item[S"ItemTypes"]->NewRow();
    	 rowNewType->Item[frmData->colItemType] = this->txtNewItemType->Text;
    	 frmData->dsMusicStore->Tables->Item[S"ItemTypes"]->Rows->Add(rowNewType);
    
    	 this->dataGrid1->DataSource = frmData->dsMusicStore;
    	 this->dataGrid1->DataMember = S"ItemTypes";
    
    	 this->txtNewItemType->Text = S"";
    	 this->txtNewItemType->Focus();
    }
  4. Save the form

Adding a Value Based on the Column Object Name

To specify the name of the column, the DataRow class is equipped with an Item property that allows you to identify a column by its object name, by its variable name, or by its index. Based on this, the DataRow::Item property is overloaded with three versions. One of the versions uses the following syntax:

public: __property void set_Item(String* columnName);

This property expects the object name of the column passed in its square brackets. When calling this property, you can assign it the desired value for the column. Here is an example:

System::Void btnNewDirector_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *rowDirector = this->dtDirectors->NewRow();

	 rowDirector->Item[S"Director"] = S"John Landis";
}

After assigning the desired value to the row, to add the new value to a table, the DataRowCollection class provides the Add() method that is overloaded with two versions. The first version of this method uses the following syntax:

public: void Add(DataRow* row);

This method simply expects you to pass the DataRow object you previously defined. Here is an example:

System::Void btnNewDirector_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *rowDirector = this->dtDirectors->NewRow();

	 rowDirector->Item[S"Director"] = S"John Landis";
	 this->dtDirectors->Rows->Add(rowDirector);
}

In the same way, you can identify each column of a table by its object name and assign it the appropriate value. Once the record is complete, you can add it to the table. Here is an example:

System::Void btnNewVideo_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *rowVideo = this->dtVideos->NewRow();

	 rowVideo->Item[S"Title"] = S"A Few Good Men";
	 rowVideo->Item[S"Director"] = S"Rob Reiner";
	 rowVideo->Item[S"YearReleased"] = __box(1993);
	 rowVideo->Item[S"Length"] = S"138 Minutes";
	 rowVideo->Item[S"Rating"] = S"R";
	 rowVideo->Item[S"Format"] = S"VHS";
	 rowVideo->Item["Category"] = S"Drama";
	 this->dtVideos->Rows->Add(rowVideo);
}

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 do this, you can use the second version of the DataRowCollection::Add() method whose syntax is:

public: virtual DataRow* Add(Object* values __gc[]);

Here is an example:

System::Void btnNewVideo_Click(System::Object *  sender, System::EventArgs *  e)
{
	 String *vdoRecord[] = { S"Fatal Attraction", S"Adrian Lyne", S"1987",
			       S"120 Minutes", S"R", S"DVD", S"Drama" };

	 this->dtVideos->Rows->Add(vdoRecord);
}

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

System::Void btnNewVideo_Click(System::Object *  sender, System::EventArgs *  e)
{
	 String *vdoNewVideo[] = { S"Her Alibi", S"Bruce Beresford", S"1989",
			             S"94 Minutes", S"PG-13", S"DVD", S"Comedy" };
	 DataRow *rowNewVideo = this->dtVideos->NewRow();
	 rowNewVideo->ItemArray = vdoNewVideo;
	 this->dtVideos->Rows->Add(rowNewVideo);
}

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

Application Data Storage

 

Introduction

In Lesson 8, we introduced lists as parts of an application and the information they contain. In this lesson, we learned how to fill such lists with information. 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.

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 List

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. 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 this method very useful and friendly.

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 to specify 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);

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.

Opening a List

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. This method opens the file and provides the XML formatting as it was done when the file was saved. 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 must 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 string.

 

Practical Learning Practical Learning: Opening an XML File

  1. Display the Categories form and double-click its Add button
  2. Change the Click event as follows:
     
    #pragma once
    
    #include "DataCenter.h"
    
    namespace MusicStore2a
    {
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace System::IO;
    using namespace System::Xml;
    
    	. . . No Change
    		
    			
    			. . . No Change
    
    	
    System::Void btnAdd_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the Data Center because 
    	 // that's where the DataSet object resides
    	 DataCenter *frmData = new DataCenter;
    	 // This is the XML file that will holds the Categories
    	 String *strFilename = S"Categories.xml";
    
    	 // If the file exists already, open it
    	 if( File::Exists(strFilename) )
    		 frmData->dsMusicStore->ReadXml(strFilename);
    
    	 // Create a new record for the Categories table
    DataRow *rowNewCategory = frmData->dsMusicStore->Tables->Item[S"Categories"]->NewRow();
    	 // Specify only the Category column since the CategoryID is auto-incrementing
    	 rowNewCategory->Item[0] = this->txtNewCategory->Text;
    	 // Add the new record to the Categories table
    	 frmData->dsMusicStore->Tables->Item[S"Categories"]->Rows->Add(rowNewCategory);
    
    	 // Update the XML file
    	 frmData->dsMusicStore->WriteXml(strFilename);
    
    	 // Display the current records of the Categories table so
    	 // the user would know what categories are already in the table
    	 this->dataGrid1->DataSource = frmData->dsMusicStore;
    	 this->dataGrid1->DataMember = S"Categories";
    
    	 // Reset the text box in case the user wants to add another category
    	 this->txtNewCategory->Text = S"";
    	 this->txtNewCategory->Focus();
    }
    };
    }
  3. Display the Item Types form and double-click its Add button
  4. Change the Click event as follows:
     
    #pragma once
    
    #include "DataCenter.h"
    
    
    namespace MusicStore2a
    {
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace System::IO;
    using namespace System::Xml;
    	
    	. . . No Change
    	
    			
    System::Void btnAdd_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 DataCenter *frmData = new DataCenter;
    	 String *strFilename = S"ItemTypes.xml";
    
    	 if( File::Exists(strFilename) )
    		 frmData->dsMusicStore->ReadXml(strFilename);
    
    	 DataRow *rowNewType = frmData->dsMusicStore->Tables->Item[S"ItemTypes"]->NewRow();
    	 rowNewType->Item[frmData->colItemType] = this->txtNewItemType->Text;
    	 frmData->dsMusicStore->Tables->Item[S"ItemTypes"]->Rows->Add(rowNewType);
    
    	 frmData->dsMusicStore->WriteXml(strFilename);
    
    	 this->dataGrid1->DataSource = frmData->dsMusicStore;
    	 this->dataGrid1->DataMember = S"ItemTypes";
    
    	 this->txtNewItemType->Text = S"";
    	 this->txtNewItemType->Focus();
    }
    
    };
    }
  5. Display the New Store Item form.
    Double-click an unoccupied area of its body and change its Load event as follows:
     
    System::Void NewStoreItem_Load(System::Object *  sender, System::EventArgs *  e)
    {				 
    	 DataCenter *frmData = new DataCenter;
    	 XmlTextReader * rdrMusicStore = 0;
    				 
    	 try {
    		 String *strFilename = S"Categories.xml";
    
    		 if( File::Exists(strFilename) )
    		 {
    			 rdrMusicStore = new XmlTextReader(strFilename);
    
    			 // Scan the XML file
    			 while (rdrMusicStore->Read())
    			 {
    				 // every time you find an element, find out what type it is
    				 // If you find a category, put it in the Categories list box
    			 if( XmlNodeType::Element && rdrMusicStore->Name->Equals(S"Category") )
    			 {
    		 this->cboCategories->Items->Add(rdrMusicStore->ReadElementString(S"Category"));
    			 }       
                    		 }
    	                }
    
                    	 strFilename = S"ItemTypes.xml";
    
                    	 if( File::Exists(strFilename) )
                    	 {
    		 rdrMusicStore = new XmlTextReader(strFilename);
    
    		 // Scan the XML file
    		 while (rdrMusicStore->Read())
    		 {
    			 // every time you find an element, find out what type it is
    			 // If you find an ItemType, put it in the Item Types list box
    			 if( XmlNodeType::Element && rdrMusicStore->Name->Equals(S"ItemType") )
    			 {
    		 this->cboItemTypes->Items->Add(rdrMusicStore->ReadElementString(S"ItemType"));
    			 }       
    		 }
                    	 }
                    }
    	 catch(XmlException *)
    	 {
    		 MessageBox::Show(S"Invalid XML file");
    	 }
    	 __finally
    	 {
    		 if( rdrMusicStore != 0 )
    			 rdrMusicStore->Close();
    	 }
    
    	 // We will generate a random number for the store item
    	 DateTime tmeNow = DateTime::Now;
    	 Random *rndNumber = new Random(tmeNow.Millisecond);
    	 String *strNumber = rndNumber->Next(100000, 999999).ToString();
    
    	 // Display the new number in the Part # text box
    	 this->txtItemNumber->Text = strNumber;
    
    	 // Disable the Create button to indicate that the item is not ready
    	 this->btnCreate->Enabled = false;
    }
  6. Return to the New Store Item form. Double-click the top New button and change its Click event as follows:
     
    System::Void btnNewCategory_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 Categories *frmCat = new Categories;
    
    	 frmCat->ShowDialog();
    			 
    	 XmlTextReader *rdrMusicStore = 0;
    				 
    	 try {
    		 String *strFilename = S"Categories.xml";
    
    		 if( File::Exists(strFilename) )
    		 {
    			 this->cboCategories->Items->Clear();
    
    			 rdrMusicStore = new XmlTextReader(strFilename);
    
    			 // Scan the XML file
    			 while (rdrMusicStore->Read())
    			 {
    		 // every time you find an element, find out what type it is
    		 // If you find a category, put it in the Categories list box
    	 if( XmlNodeType::Element && rdrMusicStore->Name->Equals(S"Category") )
    				 {
    		 String *strNew = rdrMusicStore->ReadElementString(S"Category");
    			 if( !this->cboCategories->Items->Contains(strNew) )
    				 this->cboCategories->Items->Add(strNew);
    				 }       
    			 }
    		 }
    	 }
    	 catch(XmlException *)
    	 {
    		 MessageBox::Show(S"Invalid XML file");
    	 }
    	 __finally
    	 {
    		 if( rdrMusicStore != 0 )
    			 rdrMusicStore->Close();
    	 }
    }
  7. Return to the New Store Item form. Double-click the other New button and change its Click event as follows:
     
    System::Void btnNewType_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 ItemTypes *frmTypes = new ItemTypes;
    
    	 frmTypes->ShowDialog();
    			 				 
    	 XmlTextReader *rdrMusicStore = 0;
    				 
    	 try {
    		 String *strFilename = S"ItemTypes.xml";
    
    		 if( File::Exists(strFilename) )
    		 {
    			 rdrMusicStore = new XmlTextReader(strFilename);
    
    			 while (rdrMusicStore->Read())
    			 {
    	 if( XmlNodeType::Element && rdrMusicStore->Name->Equals(S"ItemType") )
    				 {
    	 String *strNewType = rdrMusicStore->ReadElementString(S"ItemType");
    	 if( !this->cboItemTypes->Items->Contains(strNewType) )
    		 this->cboItemTypes->Items->Add(strNewType);
    				 }       
    			 }
    		 }
    	 }
    	 catch(XmlException *)
    	 {
    		 MessageBox::Show(S"Invalid XML file");
    	 }
    	 __finally
    	 {
    		 if( rdrMusicStore != 0 )
    			 rdrMusicStore->Close();
    	 }
    }
  8. Return to the New Store Item form. Double-click the Item Name text box and implement its TextChanged event as follows:
     
    System::Void txtItemName_TextChanged(System::Object *  sender, System::EventArgs *  e)
    {
    	 if( this->txtItemName->Text->Equals(S"") )
    		 this->btnCreate->Enabled = false;
    	 else
    		 this->btnCreate->Enabled = true;
    }
  9. Return to the New Store Item form. Double-click the Unit Price text box and implement its TextChanged event as follows:
     
    System::Void txtUnitPrice_TextChanged(System::Object *  sender, System::EventArgs *  e)
    {
    	 if( this->txtUnitPrice->Text->Equals(S"") )
    		 this->btnCreate->Enabled = false;
    	 else
    		 this->btnCreate->Enabled = true;
    }
  10. Return to the New Store Item form. Double-click the Item Number text box and implement its TextChanged event as follows:
     
    System::Void txtItemNumber_TextChanged(System::Object *  sender, System::EventArgs *  e)
    {
    	 if( this->txtItemNumber->Text->Equals(S"") )
    		 this->btnCreate->Enabled = false;
    	 else
    		 this->btnCreate->Enabled = true;
    }
  11. Return to the New Store Item form. Double-click its Create button and implement the event as follows:
     
    System::Void btnCreate_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the Data Center because 
    	 // that's where the DataSet object resides
    	 DataCenter *frmData = new DataCenter;
    
    	 // This is the XML file that will holds the general inventory
    	 // of the current items in the store
    	 String *strAvailableItems = S"Inventory.xml";
    
    	 // If the file exists already, open it
    	 if( File::Exists(strAvailableItems) )
    		 frmData->dsMusicStore->ReadXml(strAvailableItems);
    
    	 // Create a new record for the AvailableItems table
     DataRow *rowNewItem = frmData->dsMusicStore->Tables->Item[S"AvailableItems"]->NewRow();
    
     rowNewItem->Item[S"ItemNumber"] = this->txtItemNumber->Text;
     rowNewItem->Item[S"ItemCategory"] = this->cboCategories->Text;
    	 rowNewItem->Item[S"ItemType"] = this->cboItemTypes->SelectedIndex.ToString();
    	 rowNewItem->Item[S"ItemName"]   = this->txtItemName->Text;
    	 rowNewItem->Item[S"UnitPrice"]  = this->txtUnitPrice->Text;
    	 // Add the new record to the AvailableItems table
    	 frmData->dsMusicStore->Tables->Item[S"AvailableItems"]->Rows->Add(rowNewItem);
    
    	 // Update the XML file
    	 frmData->dsMusicStore->WriteXml(strAvailableItems);
    
    	 // Reset the controls in case the user wants to add another record
    	 this->cboCategories->SelectedIndex = -1;
    	 this->cboItemTypes->SelectedIndex  = -1;
    	 this->txtItemName->Text = S"";
    	 this->txtUnitPrice->Text = S"0.00";
    			 
    	 // We will generate a random number for the store item
    	 DateTime tmeNow = DateTime::Now;
    	 Random *rndNumber = new Random(tmeNow.Millisecond);
    	 String *strNumber = rndNumber->Next(100000, 999999).ToString();
    
    	 // Display the new number in the Part # text box
    	 this->txtItemNumber->Text = strNumber;
    
    	 // Disable the OK button to indicate that the item is not ready
    	 this->btnCreate->Enabled = false;
    }
  12. Execute the application
  13. Click the New Store Item button
  14. Click the top New button to display the Categories form and create a few categories as follows:
     
    Category
    Electric Guitar
    Acoustic Guitar
    Bass
    Keyboard
    Stands
    Cables
    Cases
    DJ Equipment
  15. Close the Categories form and open the Item Types form
  16. Create a few item types as follows:
     
    Item Type
    4-String
    5-String
    6-String
    12-String
    Solid Body
    Hollow Body
    Left-Handed
    Guitar Stand
    DJ CD Players
  17. Close the Item Types form
  18. In the New Store Item form, create the following items (let the computer generate item numbers):
     
    Category Item Type Item Name Unit Price
    Electric Guitar Solid Body Gibson Les Paul Standard Electric Guitar 1950.00
    Bass 6-String Ibanez SR506 6-String Electric Bass 595.50
    Electric Guitar Hollow Body Oscar Schmidt OE40 Hollow Body Electric Guitar 205.95
    Acoustic Guitar Left-Handed Yamaha Left-Handed FG413SL Acoustic Guitar 295.95
    Cables Instrument Cable Monster Cable S-100 Straight Instrument Cable 12.95
    Bass Combo Amps Behringer BX1200 Ultrabass Amplifier (120 Watts, 2-Channel) 150.00
    Keyboard Synthesizers Korg Triton Le 61-Key Workstation Synth 895.95
    Stands Guitar Stand String Swing Metal Guitar Wall Hanger 9.95
    Electric Guitar Solid Body Epiphone LP-100 Electric Guitar 275.95
    Keyboard Digital Piano Yamaha YDP223 88-Key Graded Hammer Piano With Bench 1490.00
    Cables Guitar Cable Spectraflex Guitar Cable 42.25
    Electric Guitar Solid Body Gibson Les Paul Classic Electric Guitar 1625.95
    Stands Guitar Stand Locking Tubular Guitar Stand 4.95
    Electric Guitar Solid Body ESP LTD Viper 400 Electric Guitar 585.50
    Acoustic Guitar 12-String Washburn J28S12DL Cumberland 12-String Guitar 650.75
    Electric Guitar Hollow Body Ibanez Artcore AF75 Electric Guitar 315.95
    Keyboard Synthesizers Korg Triton Extreme 61-Key Synth Workstation 1895.00
    Electric Guitar Solid Body Epiphone Les Paul Standard 525.95
    Stands Guitar Stand Guitar Folding Stand 12.95
    Electric Guitar Hollow Body Gibson ES-335 Reissue 1850.00
    Acoustic Guitar 12-String Martin DM12 850.00
    Stands Guitar Stand Metal Guitar Wall Hanger 9.95
    Acoustic Guitar Left Handed Yamaha FG413SL 295.95
    Electric Guitar Solid Body Gibson Faded SG Special 625.95
    Bass 4-String Ibanez SR500 525.95
    Electric Guitar Hollow Body Oscar Schmidt OE40 225.95
    Electric Guitar Left Handed Schecher C-1 450.95
    Cases Cases Les Paul Hardshell Case 39.95
    Cables Instrument Cable Hosa Dual Instrument Cable 7.25
  19. Close the forms and return to your programming environment

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 doesn't 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 where made on the records of the list(s).

Locating Records and Their Values

 

Locating a Record

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. To locate a record in the DataTable::Rows collection, the DataRowCollection class provides the Item property that is defined as follows

public: __property DataRow* get_Item(int index);

The records of a table are stored in a list (called the DataRowCollection). The first record, which in the example above has the title as "A Few Good Men" and the Director as Rob Reiner, has an index of 0. The second record has an index of 1, and so on. Here is an example of using it to retrieve the information stored in a record:

System::Void button1_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *row = this->dtVideos->Rows->Item[2];
}

When you pass an index to this property, the compiler would check whether the record exists. If a record with that index exists, its DataRow value is produced. 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.

To get the number of records that a table contains, access the Count property of its DataRowCollection. The Count property is inherited from the InternalDataCollectionBase class, which is the parent of many collection classes.

When the records of a DataTable object have been created, you can get their list as an array using its List property that is inherited from the InternalDataCollectionBase class. This property returns an ArrayList type of list.

Practical Learning Practical Learning: Locating Records

  1. Display the Purchase Order form and double-click an unoccupied area of its body away from (outside of) any group box
  2. Implement the Load event as follows:
     
    #pragma once
    
    #include "DataCenter.h"
    #include "NewStoreItem.h"
    
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace System::IO;
    using namespace System::Xml;
    
    namespace MusicStore2a
    {
    	. . . No Change 
    
    
    
    Void PurchaseOrder_Load(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the object that holds the DataSet
    	 DataCenter *frmData = new DataCenter;
    	 // Identify the file that holds the categories
    	 String *strCategories = S"Categories.xml";
    
    	 // If that file exists, then open it
    	 if( File::Exists(strCategories) )
    		 frmData->dsMusicStore->ReadXml(strCategories);
    
    	 // Just in case, empty the Categories list box
    	 this->lbxCategories->Items->Clear();
    
    	 DataRow *row = 0;
    	 // Scan the whole file to locate each category and retrieve it
    	 for(int i = 0; i < frmData->tblCategories->Rows->Count; i++)
    	 {
    		 row = frmData->tblCategories->Rows->Item[i];
    	 }
    }
    }
  3. Save all

Locating a Value

As mentioned already, a record is in fact one value or a group of values from each of the columns of the table. Consider the following table:

The "A Few Good Men" string is a value of the Title column. In the same way, "VHS" is a value of the Format column. In some circumstances, you will need to locate a particular value in order to perform an operation on it. As seen above, you can start by locating the record you need and return its DataRow object. To know the table that the record belongs to, access its DataRow::Table property. This property is declared as follows:

public: __property DataTable* get_Table();

To locate the value that a record holds under a particular column, the DataRow class provides the Item property that is overloaded with three versions (actually six, but at this time we are interested in the first three only). One of the versions of this property uses the following syntax:

public: __property Object* get_Item(String* columnName);

To use this property, pass the object name of the column in the square brackets. The following example is based on the above table. It retrieves the title of the third video and displays it in the caption of the form:

System::Void button1_Click(System::Object *  sender, System::EventArgs *  e)
{
	 DataRow *row = this->dtVideos->Rows->Item[2];
	 String  *strVideoTitle = dynamic_cast<String *>(row->Item[S"Title"]);

	 Text = strVideoTitle;
}

Instead of using the index 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::Item indexed property:

public: __property void get_Item(DataColumn* column);

This property expects the object name of the column passed in its square brackets. The third option you have is to identify the column by its index. To do this, use the following syntax of the DataRow::Item indexed property:

public: __property void get_Item(int index);

This property expects the index of the column.

 

Practical Learning Practical Learning: Locating Records

  1. Change the Load event of the Purchase Order form as follows:
     
    System::Void PurchaseOrder_Load(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the object that holds the DataSet
    	 DataCenter *frmData = new DataCenter;
    	 // Identify the file that holds the categories
    	 String *strCategories = S"Categories.xml";
    
    	 // If that file exists, then open it
    	 if( File::Exists(strCategories) )
    		 frmData->dsMusicStore->ReadXml(strCategories);
    
    	 // Just in case, empty the Categories list box
    	 this->lbxCategories->Items->Clear();
    
    	 DataRow *row = 0;
    	 // Scan the whole table to locate each record
    	 for(int i = 0; i < frmData->tblCategories->Rows->Count; i++)
    	 {
    		 row = frmData->tblCategories->Rows->Item[i];
    		 this->lbxCategories->Items->Add(dynamic_cast<String *>(row->Item[S"Category"]));
    	 }
    }
  2. Return to the Purchase Order form and double-click the Category list box
  3. Implement its SelectedIndexChanged event as follows:
     
    System::Void lbxCategories_SelectedIndexChanged(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the object that holds the DataSet
    	 DataCenter *frmData = new DataCenter;
    	 // Identify the file that holds the items
    	 String *strAvailableItems = S"Inventory.xml";
    	 // Identify the category that the user selected
    	 String *strSelectedCategory = this->lbxCategories->Text;
    
    	 // If that file exists, then open it
    	 if( File::Exists(strAvailableItems) )
    		 frmData->dsMusicStore->ReadXml(strAvailableItems);
    
    	 // Empty the Item Types list box
    	 this->lbxItemTypes->Items->Clear();
    	 // Also empty the Available Items list box
    	 this->lbxAvailableItems->Items->Clear();
    
    	 DataRow *row = 0;
    	 // Scan the whole table to locate each record
    	 for(int i = 0; i < frmData->tblAvailableItems->Rows->Count; i++)
    	 {
    		 // Get a reference to the current record
    		 row = frmData->tblAvailableItems->Rows->Item[i];
    		 // Get the name of the category of the current record
    		 String *strCurrentCategory = dynamic_cast<String *>(row->Item[S"ItemCategory"]);
    
    		 // If the current category matches the one the user selected...
    		 if( strCurrentCategory->Equals(strSelectedCategory) )
    		 {
    			 // ... then get the corresponding item type
    			 String *strType     = dynamic_cast<String *>(row->Item[S"ItemType"]);
    			 // Find out if the Item Types list box already contains the item type
    			 // If it doesn't, then put it in the Item Types list box
    			 if( !this->lbxItemTypes->Items->Contains(strType) )
    				 this->lbxItemTypes->Items->Add(strType);
    		 }
    	 }
    }
  4. Return to the Purchase Order form and double-click the Item Types list box
  5. Implement its SelectedIndexChanged event as follows:
     
    System::Void lbxItemTypes_SelectedIndexChanged(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the object that holds the DataSet
    	 DataCenter *frmData = new DataCenter;
    	 // Identify the file that holds the items
    	 String *strAvailableItems = S"Inventory.xml";
    	 // Identify the category that the user selected
    	 String *strSelectedCategory = this->lbxCategories->Text;
    	 String *strSelectedType     = this->lbxItemTypes->Text;
    
    	 // If file exists, then open it
    	 if( File::Exists(strAvailableItems) )
    		 frmData->dsMusicStore->ReadXml(strAvailableItems);
    
    	 // Empty the Available Items list box
    	 this->lbxAvailableItems->Items->Clear();
    
    	 DataRow *row = 0;
    	 // Scan the whole table to locate each record
    	 for(int i = 0; i < frmData->tblAvailableItems->Rows->Count; i++)
    	 {
    		 // Get a reference to the current record
    		 row = frmData->tblAvailableItems->Rows->Item[i];
    		 // Get the name of the category of the current record
    	String *strCurrentCategory = dynamic_cast<String *>(row->Item[S"ItemCategory"]);
    		 // Get the item type of the current record
    		 String *strCurrentType = dynamic_cast<String *>(row->Item[S"ItemType"]);
    
    		 // If the current category matches the one the user selected
    		 // and the current item type matches the type the user selected ...
    		 if( strCurrentCategory->Equals(strSelectedCategory) &&
    			 strCurrentType->Equals(strSelectedType) )
    		 {
    			 // ... then get the corresponding item name
    	 this->lbxAvailableItems->Items->Add(dynamic_cast<String *>(row->Item[S"ItemName"]));
    		 }
    	 }
    }
  6. Return to the Purchase Order form and click the Available Items list box
  7. In the Properties window, click the Events button and double-click the DoubleClick field
  8. Implement its DoubleClick event as follows:
     
    System::Void lbxAvailableItems_DoubleClick(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Get a reference to the object that holds the DataSet
    	 DataCenter *frmData = new DataCenter;
    	 // Identify the file that holds the items
    	 String *strAvailableItems = S"Inventory.xml";
    	 // Identify the item that the user selected
    	 String *strSelectedCategory = this->lbxCategories->Text;
    	 String *strSelectedType     = this->lbxItemTypes->Text;
    	 String *strSelectedName     = this->lbxAvailableItems->Text;
    
    	 // If file exists, then open it
    	 if( File::Exists(strAvailableItems) )
    		 frmData->dsMusicStore->ReadXml(strAvailableItems);
    
    	 DataRow *row = 0;
    	 // Scan the whole table to locate each record
    	 for(int i = 0; i < frmData->tblAvailableItems->Rows->Count; i++)
    	 {
    		 // Get a reference to the current record
    		 row = frmData->tblAvailableItems->Rows->Item[i];
    		 // Get the name of the category of the current record
    	String *strCurrentCategory = dynamic_cast<String *>(row->Item[S"ItemCategory"]);
    		 // Get the item type of the current record
    	 String *strCurrentType = dynamic_cast<String *>(row->Item[S"ItemType"]);
    		 // Get the name of the current item
    	 String *strCurrentName = dynamic_cast<String *>(row->Item[S"ItemName"]);
    		 // Get the item number of the current item
    	 String *strCurrentNumber = dynamic_cast<String *>(row->Item[S"ItemNumber"]);
    		 // Get the unit price of the current item
    	 String *strCurrentPrice = dynamic_cast<String *>(row->Item[S"UnitPrice"]);
    
    	 // If the current parts match the ones the user selected ...
    	 if( strCurrentCategory->Equals(strSelectedCategory) &&
    	     strCurrentType->Equals(strSelectedType) &&
                         strCurrentName->Equals(strSelectedName) )
    	 {
    		 // ... then consider the corresponding item
    		 if( this->txtItemNumber1->Text->Equals(S"") )
    		 {
    			 this->txtItemNumber1->Text = strCurrentNumber;
    			 this->txtItemName1->Text   = strCurrentName;
    			 this->txtUnitPrice1->Text  = strCurrentPrice;
    			 this->txtQuantity1->Text   = S"1";
    			 this->txtSubTotal1->Text   = strCurrentPrice;
    		 }
    		 else if( this->txtItemNumber2->Text->Equals(S"") )
    		 {
    			 this->txtItemNumber2->Text = strCurrentNumber;
    			 this->txtItemName2->Text   = strCurrentName;
    			 this->txtUnitPrice2->Text  = strCurrentPrice;
    			 this->txtQuantity2->Text   = S"1";
    			 this->txtSubTotal2->Text   = strCurrentPrice;
    		 }
    		 else if( this->txtItemNumber3->Text->Equals(S"") )
    		 {
    			 this->txtItemNumber3->Text = strCurrentNumber;
    			 this->txtItemName3->Text   = strCurrentName;
    			 this->txtUnitPrice3->Text  = strCurrentPrice;
    			 this->txtQuantity3->Text   = S"1";
    			 this->txtSubTotal3->Text   = strCurrentPrice;
    		 }
    		 else if( this->txtItemNumber4->Text->Equals(S"") )
    		 {
    			 this->txtItemNumber4->Text = strCurrentNumber;
    			 this->txtItemName4->Text   = strCurrentName;
    			 this->txtUnitPrice4->Text  = strCurrentPrice;
    			 this->txtQuantity4->Text   = S"1";
    			 this->txtSubTotal4->Text   = strCurrentPrice;
    		 }
    		 else if( this->txtItemNumber5->Text->Equals(S"") )
    		 {
    			 this->txtItemNumber5->Text = strCurrentNumber;
    			 this->txtItemName5->Text   = strCurrentName;
    			 this->txtUnitPrice5->Text  = strCurrentPrice;
    			 this->txtQuantity5->Text   = S"1";
    			 this->txtSubTotal5->Text   = strCurrentPrice;
    		 }
    		 else // if( this->txtItemNumber6->Text->Equals(S"") )
    		 {
    			 this->txtItemNumber6->Text = strCurrentNumber;
    			 this->txtItemName6->Text   = strCurrentName;
    			 this->txtUnitPrice6->Text  = strCurrentPrice;
    			 this->txtQuantity6->Text   = S"1";
    			 this->txtSubTotal6->Text   = strCurrentPrice;
    		 }
    	 }
    	 }
    }
  9. Execute the application and perform a few transactions

Record Maintenance

Once a table has been filled with records, you can perform maintenance operations on it such as changing some records or removing others. To remove a record from a table, you can call the DataRowCollection::Remove() method. Its syntax is:

public: void Remove(DataRow *row);

This method takes as argument a DataRow object and checks whether the table contains. If that record exists, it gets deleted, including all of its entries for each column. When calling this method, you must pass an exact identification of the record. If you don't have that identification, you can delete a record based on its index. To do this, you would call the DataRowCollection::RemoveAt() method. Its syntax is:

public: void RemoveAt(int index);

This method takes as argument the index of the record you want to delete. If a record with that index exists, it would be deleted.

To delete all records of a table, call the DataRowCollection::Clear() method. Its syntax is:

public: void Clear();

This method is used to clear the table of all records.

 

Home Copyright 2005 FunctionX, Inc.