Home

Overview of Collections

 

Indexers

 

Introduction

An indexer, also called an indexed property, is a class's property that allows you to access a member variable of a class using the features of an array. To create an indexed property, start the class like any other. In the body of the class, create a field that is an array. The array can be of a primitive type or composite. Obviously if you want to use a composite type, you can use one of the many built-in .NET Framework classes or you must first create your class. Here is an example:

enum class Genders { Male, Female, Unspecified };

public ref class CStudent
{
public:
    int StudentID;
    String ^ FirstName;
    String ^ LastName;
    Genders Gender;

    CStudent(int ID, String ^ fName, String ^lName, Genders gdr)
    {
	StudentID = ID;
	FirstName = fName;
	LastName  = lName;
	Gender    = gdr;
    }
};

public ref class CStudents
{
    array<CStudent ^> ^ individuals;

public:
    CStudents();
};

CStudents::CStudents()
{
    individuals = gcnew array<CStudent ^>(5);
}

In the body of the class, create a property named default with its accessor(s). The default property must be the same type as the field it will refer to. The property must take a parameter as an array. This means that it must have square brackets. Inside of the brackets, include the parameter you will use as index to access the members of the array.

You usually access the members of an array using an integer-based index. Therefore, you can use an int type as the index of the array. This would be done as follows:

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    property CStudent ^ default[int]
    {
    }
};

If you want the property to be read-only, include only a get accessor. In the get accessor, you should return an element of the array the property refers to. This would be done as follows:

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int]
    {
	CStudent ^ get(int i)
        {
            return individuals[i]; 
        }
    }
};

If you want to create an indexer that can only receive values, add it a set accessor only. Here is an example:

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int]
    {
	void set(int i, CStudent ^ value)
	{
	    individuals[i] = value;
	}
    }
};

If you want to create an indexed property that can both receive values and provide values, that is, if you want to create a read/write indexed property, create both a get and a set accessors. Here is an example:

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int]
    {
	CStudent ^ get(int i)
        {
            return individuals[i]; 
        }

	void set(int i, CStudent ^ value)
	{
	    individuals[i] = value;
	}
    }
};

CStudents::CStudents()
{
    individuals = gcnew array<CStudent ^>(5);
}

After creating a read/write indexer, you can assign its values outside of the class. In other words, clients of the class can change the values to its elements. Remember that the advantage of an indexed property is that each element of the arrayed field can be accessed from the instance of the class by directly applying the square brackets and the (appropriate) index to it. Here is an example:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;

enum class Genders { Male, Female, Unknown };

public ref class CStudent
{
public:
    int StudentID;
    String ^ FirstName;
    String ^ LastName;
    Genders Gender;

    CStudent(int ID, String ^ fName, String ^lName, Genders gdr)
    {
	StudentID = ID;
	FirstName = fName;
	LastName  = lName;
	Gender    = gdr;
    }
};

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int]
    {
	CStudent ^ get(int i)
        {
            return individuals[i]; 
        }

	void set(int i, CStudent ^ value)
	{
	    individuals[i] = value;
	}
    }
};

CStudents::CStudents()
{
    individuals = gcnew array<CStudent ^>(5);
}

public ref class CExercise : public Form
{
    Button ^ btnLoad;
    DataGridView ^ dgvValues;

public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
        btnLoad = gcnew Button;
        btnLoad->Text = "Load";
        btnLoad->Location = Point(12, 12);
        btnLoad->Click += gcnew EventHandler(this, &CExercise::btnLoadClick);

        dgvValues = gcnew DataGridView;
        dgvValues->Location = Point(12, 44);
        dgvValues->Size = System::Drawing::Size(270, 200);
        dgvValues->Anchor = AnchorStyles::Left | AnchorStyles::Top |
                            AnchorStyles::Right | AnchorStyles::Bottom;

        Text = "Students Records";
        Controls->Add(btnLoad);
        Controls->Add(dgvValues);
        Size = System::Drawing::Size(320, 280);
        StartPosition = FormStartPosition::CenterScreen;
    }

    void btnLoadClick(Object ^ sender, EventArgs ^ e)
    {
        CStudents ^ people = gcnew CStudents;

        people[0] = gcnew CStudent(72947, "Paulette", "Cranston", Genders::Female);
        people[1] = gcnew CStudent(70854, "Harry", "Kumar", Genders::Male);
        people[2] = gcnew CStudent(27947, "Jules", "Davidson", Genders::Male);
        people[3] = gcnew CStudent(62835, "Leslie", "Harrington", Genders::Unknown);
        people[4] = gcnew CStudent(92958, "Ernest", "Colson", Genders::Male);

        dgvValues->Columns->Add("StudendNumber", "Student ID");
        dgvValues->Columns->Add("FirstName", "First Name");
        dgvValues->Columns->Add("Last Name", "Last Name");
        dgvValues->Columns->Add("Gender", "Gender");

        for (int i = 0; i < 5; i++)
        {
            dgvValues->Rows->Add();

            dgvValues->Rows[i]->Cells[0]->Value = people[i]->StudentID.ToString();
            dgvValues->Rows[i]->Cells[1]->Value = people[i]->FirstName;
            dgvValues->Rows[i]->Cells[2]->Value = people[i]->LastName;
            dgvValues->Rows[i]->Cells[3]->Value = people[i]->Gender.ToString();
        }
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

This would produce:

Students Records

Array-Based and Collection-Based Indexers

When using an indexed property whose field is array-based, you can access only up to the number of elements specified when creating the indexer. In our example, that would be 5. If you try to access more elements than that, you would receive an IndexOutOfRangeException exception. And because, when using the indexed property, it is treated as a normal class and not an array, you cannot call the Array::Resize() member function to increase the number of elements that the variable can hold. If you want to go beyond the number of elements primarily specified, you have various alternatives. You can specify a higher number of elements when creating the indexer. Here is an example:

public ref class CStudents
{
    array<CStudent ^> ^ individuals;

public:
    CStudents();
};

CStudents::CStudents()
{
    individuals = gcnew array<CStudent ^>(100);
}

The disadvantage to this approach is that every time this program runs, it would use more memory than it needs. Of course this means that it is not a professional technique of solving a problem. An alternative is to create your own means of increasing the number of elements that the variable can hold. Here is an example:

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int]
    {
	CStudent ^ get(int i)
        {
            return individuals[i]; 
        }

	void set(int i, CStudent ^ value)
	{
	    individuals[i] = value;
	}
    }

    void Increase()
    {
        Array::Resize<CStudent ^>(individuals, individuals->Length + 5);
    }
};

After doing this, whenever you know you are about to access an increased number of elements, you can simply apply your means of increasing the size. Here is an example:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;

enum class Genders { Male, Female, Unknown };

public ref class CStudent
{
public:
    int StudentID;
    String ^ FirstName;
    String ^ LastName;
    Genders Gender;

    CStudent(int ID, String ^ fName, String ^lName, Genders gdr)
    {
	StudentID = ID;
	FirstName = fName;
	LastName  = lName;
	Gender    = gdr;
    }
};

public ref class CStudents
{
private:
    array<CStudent ^> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int]
    {
	CStudent ^ get(int i)
        {
            return individuals[i]; 
        }

	void set(int i, CStudent ^ value)
	{
	    individuals[i] = value;
	}
    }

    void Increase()
    {
        Array::Resize<CStudent ^>(individuals, individuals->Length + 5);
    }
};

CStudents::CStudents()
{
    individuals = gcnew array<CStudent ^>(5);
}


public ref class CExercise : public Form
{
    Button ^ btnLoad;
    DataGridView ^ dgvValues;

public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
        btnLoad = gcnew Button;
        btnLoad->Text = "Load";
        btnLoad->Location = Point(12, 12);
        btnLoad->Click += gcnew EventHandler(this, &CExercise::btnLoadClick);

        dgvValues = gcnew DataGridView;
        dgvValues->Location = Point(12, 44);
        dgvValues->Size = System::Drawing::Size(270, 200);
        dgvValues->Anchor = AnchorStyles::Left | AnchorStyles::Top |
                            AnchorStyles::Right | AnchorStyles::Bottom;

        Text = "Students Records";
        Controls->Add(btnLoad);
        Controls->Add(dgvValues);
        Size = System::Drawing::Size(320, 280);
        StartPosition = FormStartPosition::CenterScreen;
    }

    void btnLoadClick(Object ^ sender, EventArgs ^ e)
    {
        CStudents ^ people = gcnew CStudents;

        people[0] = gcnew CStudent(72947, "Paulette", "Cranston", Genders::Female);
        people[1] = gcnew CStudent(70854, "Harry", "Kumar", Genders::Male);
        people[2] = gcnew CStudent(27947, "Jules", "Davidson", Genders::Male);
        people[3] = gcnew CStudent(62835, "Leslie", "Harrington", Genders::Unknown);
        people[4] = gcnew CStudent(92958, "Ernest", "Colson", Genders::Male);

        people->Increase();

        people[5] = gcnew CStudent(91749, "Joyce", "Landers", Genders::Female);
        people[6] = gcnew CStudent(29749, "Patrice", "Abanda", Genders::Unknown);
        people[7] = gcnew CStudent(24739, "Frank", "Thomasson", Genders::Male);

        dgvValues->Columns->Add("StudendNumber", "Student ID");
        dgvValues->Columns->Add("FirstName", "First Name");
        dgvValues->Columns->Add("Last Name", "Last Name");
        dgvValues->Columns->Add("Gender", "Gender");

        for (int i = 0; i < 8; i++)
        {
            dgvValues->Rows->Add();

            dgvValues->Rows[i]->Cells[0]->Value = people[i]->StudentID.ToString();
            dgvValues->Rows[i]->Cells[1]->Value = people[i]->FirstName;
            dgvValues->Rows[i]->Cells[2]->Value = people[i]->LastName;
            dgvValues->Rows[i]->Cells[3]->Value = people[i]->Gender.ToString();
        }
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

One more alternative to this problem consists of creating the indexer as a collection.

Multi-Parameterized Indexed Properties

Instead of a single parameter, you can create an indexed property that takes more than one parameter. To start, you can declare the array as a field of a class. After declaring the array, create a default property that takes the parameters. In the body of an accessor (get or set), use the parameter as appropriately as you see fit. At a minimum, for a get accessor, you can return the value of the array using the parameters based on the rules of a two-dimensional array. Here is an example for an indexed property that relates to a two-dimensional array:

public ref class CStudents
{
private:
    array<CStudent ^, 2> ^ individuals;

public:
    CStudents();

    property CStudent ^ default[int, int]
    {
	CStudent ^ get(int i, int j)
        {
            return individuals[i, j]; 
        }

	void set(int i, int j, CStudent ^ value)
	{
	    individuals[i, j] = value;
	}
    }
};

CStudents::CStudents()
{
    individuals = gcnew array<CStudent ^, 2>(2, 4);
}

 After creating the property, you can access each element of the array by applying the square brackets to an instance of the class. Here is an example:

void btnLoadClick(Object ^ sender, EventArgs ^ e)
{
    CStudents ^ people = gcnew CStudents;

    people[0, 0] = gcnew CStudent(72947, "Paulette", "Cranston", Genders::Female);
    people[0, 1] = gcnew CStudent(70854, "Harry", "Kumar", Genders::Male);
    people[0, 2] = gcnew CStudent(27947, "Jules", "Davidson", Genders::Male);
    people[0, 3] = gcnew CStudent(62835, "Leslie", "Harrington", Genders::Unknown);
    people[1, 0] = gcnew CStudent(92958, "Ernest", "Colson", Genders::Male);
    people[1, 1] = gcnew CStudent(91749, "Joyce", "Landers", Genders::Female);
    people[1, 2] = gcnew CStudent(29749, "Patrice", "Abanda", Genders::Unknown);
    people[1, 3] = gcnew CStudent(24739, "Frank", "Thomasson", Genders::Male);
}

Remember that one of the most valuable features of an indexed property is that, when creating it, you can make it return any primitive type and you can make it take any parameter of your choice. Also, the parameters of a multi-parameter indexed property do not have to be the same type. One can be a character while the other is a bool type; one can be a double while the other is a short, one can be an integer while the other is a string. When defining the property, you must apply the rules of both the member functions and the arrays.

Introduction to .NET Collections

 

Overview

A collection, or a list, is a series of items. The items can be made of names, numbers, or anything. Normally, the items should (must) be of the same type or they should share a structure. Many controls we will study use lists. That's why it is important to be familiar with collections.

To use a collection, you have two primary options. You can create your own class or you can use one of the built-in collection classes of the .NET Framework. If you decide to create your own class, you still have two alternatives. You can create a class from scratch or you can implement one (or more) of the built-in .NET Framework's interfaces. If you decide to use one of the .NET Framework's built-in collection classes, you can use it "as is" or you can expand it by adding custom functionality. As you can see, it is not particularly difficult to get a collection in your application. Probably the most diffilcult decision to make is what approach to use.

As mentioned already, you can create your own collection class. Fortunately, the .NET Framework provides an impressive collection of interfaces and classes. Except for the very valuable Array class, most normal collection classes are defined in the System::Collections namespace. Many generic classes are defined in the System::Collections::Generic namespace. Therefore, in order to use one these classes in your application, make sure that either you include their namespace in the file or you qualify the name of the class when declaring a variable. Here is an example:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;

public ref class CExercise : public Form
{
public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
        Text = "Exercise";
        Size = System::Drawing::Size(500, 300);
        StartPosition = FormStartPosition::CenterScreen;
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

Introduction to Collection-Based Classes

In the .NET Framework, the ICollection interface makes it possible to know the size of a collection. To support the ability to enumerate the members of a list, the ICollection interface derives from IEnumerable, thus getting its iteration ancestry.

The IList interface is the most common parent used to create a collection class. It provides all the primary functionality of a list. It is equipped to count the number of items in a list and the ability to access an item. The IList interface is equipped with member functions to add an item to the end of a list, to insert an item at any appropriate position inside the list, to check the existence of an item in the list, to delete one item from the list, or to remove all items from a collection.

To support the creation of any kind of list, one of the classes that the .NET Framework provides is the ArrayList structured as follows:

public ref class ArrayList : IList, 
                             ICollection,
                             IEnumerable,
                             ICloneable

The ArrayList class is defined in the System::Collections namespace. If you prefer to use a generic class, the .NET Framework provides the List<> class that is a member of the System::Collections::Generic namespace:

generic<typename T>
public ref class List : IList<T>,
			ICollection<T>,
			IEnumerable<T>,
			IList,
			ICollection,
			IEnumerable

Obviously before using a collection class, you must declare a variable for it, and you should allocate memory for it using the gcnew operator. Here is an example:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;

public ref class CCourse
{
public:
    String ^ CourseCode;
    String ^ CourseName;
    int Credits;

    CCourse();
    CCourse(String ^ code, String ^ name, int semesterHours);
};

CCourse::CCourse()
{
    CourseCode = "COLL 101";
    CourseName = "Unknown";
    Credits = 0;
}

CCourse::CCourse(String ^ code, String ^ name, int semesterHours)
{
    CourseCode = code;
    CourseName = name;
    Credits = semesterHours;
}

public ref class CExercise : public Form
{
    List<CCourse ^> ^ CourseCatalog;

public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
        Text = "Exercise";
        Size = System::Drawing::Size(500, 300);
        StartPosition = FormStartPosition::CenterScreen;
    }

    void FormLoaded(Object ^ sender, EventArgs ^ e)
    {
	CourseCatalog = gcnew List<CCourse ^>;
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

Notice that both the ArrayList and the List<> classes implement the ICollection, the IList, and the IEnumerable interfaces. Either class can be used to add, locate, or remove an item from a list. These classes provide many other valuable operations routinely done on a list. Additionally, the List<> class implement the IList<>, the ICollection<>, and the IEnumerable<> generic interfaces.

Thanks to their flexibilities, ArrayList and List<> are the most used classes to create lists of items of any kind in a .NET application. The routine operations found in these classes are the same found in many other collection-based classes that use collections. We will see examples with many list-based controls in later lessons.

In the System::Collections namespace, the IEnumerator interface provides the ability to visit each member of a collection. The IEnumerable interface provides functionality to iterate through the members of a list. To make this possible, the IEnumerable interface is equipped with a member function named GetEnumerator, which is of type IEnumerator. The System::Collections::Generic namespace provides additional collection interfaces.

 
 
 

The Characteristics of a Collection

 

Adding an Item

A list is meant to hold one or more items created and added to it. To support this operation, the IList class is equipped with a member function named Add that the collection classes must implement. The syntax of the Add() member function is:

int Add(Object^ value);

The Add() member function takes one argument that is the item to be added. You should not be concerned whether the list is empty or full. The compiler takes care of everything behind the scenes. Here is an example of calling the Add() member function of List<> collection:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;

public ref class CCourse
{
public:
    String ^ CourseCode;
    String ^ CourseName;
    int Credits;

    CCourse();
    CCourse(String ^ code, String ^ name, int semesterHours);
};

CCourse::CCourse()
{
    CourseCode = "COLL 101";
    CourseName = "Unknown";
    Credits = 0;
}

CCourse::CCourse(String ^ code, String ^ name, int semesterHours)
{
    CourseCode = code;
    CourseName = name;
    Credits = semesterHours;
}

public ref class CExercise : public Form
{
private:
    Button ^ btnAdd;
    List<CCourse ^> ^ CourseCatalog;

public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	btnAdd = gcnew Button;
	btnAdd->Text = "Add";
	btnAdd->Location = Point(20, 20);
	btnAdd->Click += gcnew EventHandler(this, &CExercise::btnAddClick);

        Text = "Exercise";
	Controls->Add(btnAdd);
	Load += gcnew EventHandler(this, &CExercise::FormLoaded);
        Size = System::Drawing::Size(500, 300);
        StartPosition = FormStartPosition::CenterScreen;
    }

    void FormLoaded(Object ^ sender, EventArgs ^ e)
    {
	CourseCatalog = gcnew List<CCourse ^>;
    }

    void btnAddClick(Object ^ sender, EventArgs ^ e)
    {
        CCourse ^ one = gcnew CCourse("CMSC 101", "Introductory Computer Science", 3);
        CourseCatalog->Add(one);
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

Adding a Range of Items

Instead of adding just one item in the collection, you can first create a list and add it at once. To support this operation, most collection classes are equipped with a member function named AddRange. The syntax of the AddRange() member function of the List<> class is:

public:
    void AddRange(IEnumerable<T>^ collection);

This member function takes an ICollection object as argument. This means that you can pass a variable whose type implements the ICollection interface, such as an array. Here is an example:

void btnAddClick(Object ^ sender, EventArgs ^ e)
{
    array<CCourse ^> ^ courses = gcnew array<CCourse ^>(4);
    
    courses[0] = gcnew CCourse("BMGT 304",
    			       "Managing E-Commerce in Organizations",
     			       3);
    courses[1] = gcnew CCourse("ECON 201",
     			       "Principles of Macroeconomics",
     			       3);
    courses[2] = gcnew CCourse("BMGT 324",
			"Introduction to Entrepreneurship: Starting a Small Business",
      			       1);
    courses[3] = gcnew CCourse("CMST 306",
     			       "Introduction to Visual Basic Programming",
      			       3);

    CourseCatalog->AddRange(courses);
}

Inserting Items

When the Add() member function is called, it adds a new item to the end of the collection. Sometimes, you want to add the new item inside the list at a position of your choice. To help you do this, the List<> provides the Insert() member function. Its syntax is:

public:
    virtual void Insert(int index, T item) sealed;

The Insert() member function is used to insert one item inside the list. If you have a collection to insert, you can call the InsertRange() member function whose syntax is:

public:
    void InsertRange(int index, IEnumerable<T>^ collection);

The Size of a List

The size of a list is the number of items it contains. To provide this information, the IList interface provides a property named Count that the implementers inherit. The Count property is of type int. This property is only used to provide information. You cannot change the number of items in the list by assigning a number to this property. The number of items automatically increases when a new item has been added and it decreases when an item is deleted.

Getting an Item

The IList class is equipped with an indexed property that makes it possible to access any member of its variable using the square brackets [] applied to the variable. Here is an example:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;

public ref class CCourse
{
public:
    String ^ CourseCode;
    String ^ CourseName;
    int Credits;

    CCourse();
    CCourse(String ^ code, String ^ name, int semesterHours);
};

CCourse::CCourse()
{
    CourseCode = "COLL 101";
    CourseName = "Unknown";
    Credits = 0;
}

CCourse::CCourse(String ^ code, String ^ name, int semesterHours)
{
    CourseCode = code;
    CourseName = name;
    Credits = semesterHours;
}

public ref class CExercise : public Form
{
private:
    Button ^ btnAdd;
    DataGridView ^ dgvCourses;
    List<CCourse ^> ^ CourseCatalog;

public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	btnAdd = gcnew Button;
	btnAdd->Text = "Add";
	btnAdd->Location = Point(10, 10);
	btnAdd->Click += gcnew EventHandler(this, &CExercise::btnAddClick);

        dgvCourses = gcnew DataGridView;
        dgvCourses->Location = Point(12, 44);
        dgvCourses->Size = System::Drawing::Size(480, 200);

        Text = "Exercise";
	Controls->Add(btnAdd);
	Controls->Add(dgvCourses);
        StartPosition = FormStartPosition::CenterScreen;
	Load += gcnew EventHandler(this, &CExercise::FormLoaded);
        Size = System::Drawing::Size(520, 300);
        dgvCourses->Anchor = AnchorStyles::Left | AnchorStyles::Top |
                             AnchorStyles::Right | AnchorStyles::Bottom;
    }

    void FormLoaded(Object ^ sender, EventArgs ^ e)
    {
        dgvCourses->Columns->Add("CourseCode", "Course Code");
        dgvCourses->Columns[0]->Width = 95;
        dgvCourses->Columns->Add("CourseName", "Course Name");
        dgvCourses->Columns[1]->Width = 280;
        dgvCourses->Columns->Add("Credits", "Credits");
        dgvCourses->Columns[2]->Width = 50;

	CourseCatalog = gcnew List<CCourse ^>;
    }

    void ShowCourses()
    {
        for (int i = 0; i < CourseCatalog->Count; i++)
        {
            dgvCourses->Rows->Add();

            dgvCourses->Rows[i]->Cells[0]->Value = CourseCatalog[i]->CourseCode;
            dgvCourses->Rows[i]->Cells[1]->Value = CourseCatalog[i]->CourseName;
            dgvCourses->Rows[i]->Cells[2]->Value = CourseCatalog[i]->Credits.ToString();
        }
    }

    void btnAddClick(Object ^ sender, EventArgs ^ e)
    {
        CCourse ^ one = gcnew CCourse("CMSC 101", "Introductory Computer Science", 3);
        CourseCatalog->Add(one);

        array<CCourse ^> ^ courses = gcnew array<CCourse ^>(4);
    
        courses[0] = gcnew CCourse("BMGT 304", "Managing E-Commerce in Organizations", 3);
        courses[1] = gcnew CCourse("ECON 201", "Principles of Macroeconomics", 3);
        courses[2] = gcnew CCourse("BMGT 324", "Introduction to Entrepreneurship: Starting a Small Business", 1);
        courses[3] = gcnew CCourse("CMST 306", "Introduction to Visual Basic Programming", 3);

        CourseCatalog->AddRange(courses);
        ShowCourses();
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

School Catalog

For Each Item

The IList class is equipped with a member function named GetEnumerator. This makes it possible to use for each to iterate through the collection. The GetEnumerator() returns an object of type IEnumerable. Here is an example:

void ShowCourses()
{
    int i = 0;
    dgvCourses->Rows->Clear();
		
    for each(CCourse ^ one in CourseCatalog)
    {
        dgvCourses->Rows->Add();

        dgvCourses->Rows[i]->Cells[0]->Value = one->CourseCode;
        dgvCourses->Rows[i]->Cells[1]->Value = one->CourseName;
        dgvCourses->Rows[i]->Cells[2]->Value = one->Credits.ToString();
        i++;
    }
}

As an alternative, the List<> class provides a member function named ForEach. Its syntax is:

public:
    void for each(Action<T>^ action);

This member function needs a predicate that specifies what action to perform on each member of the collection.

Checking the Existence of an Item

After a collection has been created, you may want to know whether it contains a certain element. To assist you with this, the IList interface provides a member function named Contains that its implements inherit. The syntax of the Contains() member function:

public:
    virtual bool Contains(T item) sealed;

This member function takes one argument as the item to look for. If the item is found in the collection, the member function returns true. If there is no such an item in the list, the member function returns false.

To use this member function, in your application, you should override the Equals() member function in your class. There are many ways you can implement it. At a minimum, you can create a conditional statement that checks if a simple condition is met. If so, the member function can return true. Otherwise, it would return false. Once you have done this, you can then call the Contains() member function on your List<> variable. Here is an example:

#include <windows.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections::Generic;

public ref class CCourse
{
public:
    String ^ CourseCode;
    String ^ CourseName;
    int Credits;

    CCourse();
    CCourse(String ^ code);
    CCourse(String ^ code, String ^ name, int semesterHours);

    virtual bool Equals(Object ^obj) override;
};

CCourse::CCourse()
{
    CourseCode = "COLL 101";
    CourseName = "Unknown";
    Credits = 0;
}

CCourse::CCourse(String ^ code)
{
    CourseCode = code;
    CourseName = "Unknown";
    Credits    = 0;
}

CCourse::CCourse(String ^ code, String ^ name, int semesterHours)
{
    CourseCode = code;
    CourseName = name;
    Credits = semesterHours;
}

bool CCourse::Equals(Object ^ obj)
{
    CCourse ^ current = reinterpret_cast<CCourse ^>(obj);

    if(current->CourseCode == CourseCode)
        return true;
    else
        return false;
}

public ref class CExercise : public Form
{
private:
    Button ^ btnCheck;
	DataGridView ^ dgvCourses;
    List<CCourse ^> ^ CourseCatalog;

public:
    CExercise()
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	btnCheck = gcnew Button;
	btnCheck->Text = "Check";
	btnCheck->Location = Point(10, 10);
	btnCheck->Click += gcnew EventHandler(this, &CExercise::btnCheckClick);

        dgvCourses = gcnew DataGridView;
        dgvCourses->Location = Point(12, 44);
        dgvCourses->Size = System::Drawing::Size(480, 200);

        Text = "Exercise";
	Controls->Add(btnCheck);
	Controls->Add(dgvCourses);
        StartPosition = FormStartPosition::CenterScreen;
	Load += gcnew EventHandler(this, &CExercise::FormLoaded);
        Size = System::Drawing::Size(520, 300);
        dgvCourses->Anchor = AnchorStyles::Left | AnchorStyles::Top |
                             AnchorStyles::Right | AnchorStyles::Bottom;
    }

    void FormLoaded(Object ^ sender, EventArgs ^ e)
    {
        dgvCourses->Columns->Add("CourseCode", "Course Code");
        dgvCourses->Columns[0]->Width = 95;
        dgvCourses->Columns->Add("CourseName", "Course Name");
        dgvCourses->Columns[1]->Width = 280;
        dgvCourses->Columns->Add("Credits", "Credits");
        dgvCourses->Columns[2]->Width = 50;

	CourseCatalog = gcnew List<CCourse ^>;
        CCourse ^ one = gcnew CCourse("CMSC 101", "Introductory Computer Science", 3);
        CourseCatalog->Add(one);

        array<CCourse ^> ^ courses = gcnew array<CCourse ^>(4);
    
        courses[0] = gcnew CCourse("BMGT 304",
        	"Managing E-Commerce in Organizations", 3);
        courses[1] = gcnew CCourse("ECON 201", "Principles of Macroeconomics", 3);
        courses[2] = gcnew CCourse("BMGT 324",
        	"Introduction to Entrepreneurship: Starting a Small Business", 1);
        courses[3] = gcnew CCourse("CMST 306",
            "Introduction to Visual Basic Programming", 3);

        CourseCatalog->AddRange(courses);
        ShowCourses();
    }
	
    static void Display(CCourse ^ sample)
    {
        MessageBox::Show(String::Format("Course Code:\t{0}\n" +
                                        "Course Name:\t{1}\nCredits:\t\t{2}",
                                        sample->CourseCode, sample->CourseName,
                                        sample->Credits),
                                        "Course Catalog",
                                        MessageBoxButtons::OK, MessageBoxIcon::Information);
    }

    void ShowCourses()
    {
        int i = 0;
        dgvCourses->Rows->Clear();
		
        for each(CCourse ^ one in CourseCatalog)
        {
            dgvCourses->Rows->Add();

            dgvCourses->Rows[i]->Cells[0]->Value = one->CourseCode;
            dgvCourses->Rows[i]->Cells[1]->Value = one->CourseName;
            dgvCourses->Rows[i]->Cells[2]->Value = one->Credits.ToString();
            i++;
        }
    }

    void btnCheckClick(Object ^ sender, EventArgs ^ e)
    {
	CCourse ^ sample = gcnew CCourse("BMGT 324");

        if(CourseCatalog->Contains(sample))
            MessageBox::Show("The list contains this course already",
                                "Course Catalog",
                                MessageBoxButtons::OK, MessageBoxIcon::Information);
        else
            MessageBox::Show("That course was not yet added to the catalog",
                                "Course Catalog",
                                MessageBoxButtons::OK, MessageBoxIcon::Information);
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
		     int nCmdShow)
{
    Application::Run(gcnew CExercise);

    return 0;
}

School Catalog

void btnCheckClick(Object ^ sender, EventArgs ^ e)
{
    CCourse ^ sample = gcnew CCourse("BMGT 320");

    if(CourseCatalog->Contains(sample))
        MessageBox::Show("The list contains this course already",
                         "Course Catalog",
                         MessageBoxButtons::OK, MessageBoxIcon::Information);
    else
        MessageBox::Show("That course was not yet added to the catalog",
                         "Course Catalog",
                         MessageBoxButtons::OK, MessageBoxIcon::Information);
}

School Catalog

Alternatively, you can implement an Equals() member function that checks as many conditions as you want.

As an alternative to the Contains() member function, the List<> class is equipped with a member function named Exists. Its syntax is:

public:
    bool Exists(Predicate<T>^ match);

As mentioned for arrays, this member function needs a predicate that would indicate how to check that an item exists in the collection.

Deleting an Item

Deleting an item consists of removing from a list. To support this operation, the IList interface provides the Remove() member function that its implementers must define. Its syntax is:

public:
    virtual bool Remove(T item) sealed;

This member function takes one argument that represents the item to be deleted. Of course, the item must exists in the list. To use this member function, your class should override the Equals() member function. You can then pass an object to this member function. Here is an example:

void btnDeleteClick(Object ^ sender, EventArgs ^ e)
{
    CCourse ^ one = gcnew CCourse("ECON 201");

    CourseCatalog->Remove(one);
    ShowCourses();
}

Instead of passing the exact object you want to delete, you can specify the index of the item. To make this possible, the IList interface provides a member function named RemoveAt. Its syntax:

public:
    virtual void RemoveAt(int index) sealed;

This time, the member function takes a constant integer. If there is an item at that index, the compiler deletes it. Here is an example:

void btnDeleteClick(Object ^ sender, EventArgs ^ e)
{
    CourseCatalog->RemoveAt(2);
    ShowCourses();
}

If you pass an invalid index, the compiler throws an ArgumentOutOfRangeException exception.

Deleting all Items

The Remove() and the RemoveAt() member functions are used to delete one item. To allow you to remove everything from a list, the IList interface provides the Clear() member function. Its syntax is:

public:
    virtual void Clear() sealed;

When called, this member function empties the collection and sets its count of items to 0.

 
 
   
 

Home Copyright © 2010-2012 FunctionX Home