Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Visual Basic 2005 (2006)

.pdf
Скачиваний:
219
Добавлен:
17.08.2013
Размер:
14.97 Mб
Скачать

Chapter 5

If a customer has been selected, you prompt the user to confirm the deletion:

‘Prompt the user to delete the selected customer

If MessageBox.Show(“Are you sure you want to delete “ & _ SelectedCustomer.Name & “?”, “Structure Demo”, _ MessageBoxButtons.YesNo, MessageBoxIcon.Question) = _ DialogResult.Yes Then

If the user does want to delete the customer, you get a return value from MessageBox.Show equal to DialogResult.Yes. Then you declare a customer structure to save the customer to be deleted and populate that structure with the selected customer:

‘Get the customer to be deleted

Dim objCustomerToDelete As Customer = SelectedCustomer

The Remove method of the ArrayList can then be used to remove the selected customer:

‘Remove the customer from the ArrayList objCustomers.Remove(objCustomerToDelete)

You also use a similar technique to remove the customer from the list box as well:

‘Remove the customer from the ListBox lstCustomers.Items.Remove(objCustomerToDelete)

Showing Items in the ArrayList

For completeness, you’ll want to add one more piece of functionality to enhance the user interface of your application. In the next Try It Out, you’ll add code in the SelectedIndexChanged event for the Customers list box. Every time you select a new customer, the customer’s details will be displayed in the text boxes on the form.

Try It Out

Showing Details of the Selected Item

1.Using the Forms Designer, double-click the list box. This will create a new SelectedIndexChanged event handler. Add the highlighted code:

Private Sub lstCustomers_SelectedIndexChanged( _

ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles lstCustomers.SelectedIndexChanged

‘Display the customer details

DisplayCustomer(SelectedCustomer)

End Sub

2.Run the project and click the Test button to populate the list box. Now when you select a customer in the list box, that customer’s information will appear in the fields at the bottom of the form, as shown in Figure 5-19.

156

Working with Data Structures

Figure 5-19

Working with Collections

The ArrayList is a kind of collection, which the .NET Framework uses extensively. A collection is a way of easily creating ad hoc groups of similar or related items. If you take a look back at your Structure Demo code and peek into the CreateCustomer method, you’ll notice that when adding items to the ArrayList and to the list box, you use a method called Add:

‘Add the new customer to the list objCustomers.Add(objNewCustomer)

‘Add the new customer to the ListBox control lstCustomers.Items.Add(objNewCustomer)

The code that deletes a customer uses a method called Remove on both objects:

‘Remove the customer from the ArrayList objCustomers.Remove(objCustomerToDelete)

‘Remove the customer from the ListBox lstCustomers.Items.Remove(objCustomerToDelete)

Microsoft is very keen to see developers use the collection paradigm whenever they need to work with a list of items. They also keen to see collections work in the same way, irrespective of what they actually hold — which is why you use Add to add an item and Remove to remove an item, even though you’re using a System.Collections.ArrayList object in one case and a System.Windows.Forms.List Box.ObjectCollection object in another. Microsoft has taken a great deal of care with this feature when building the .NET Framework.

Consistency is good — it allows developers to map an understanding of one thing and use that same understanding with a similar thing. When designing data structures for use in your application, you should take steps to follow the conventions that Microsoft has laid down. For example, if you have a collection class and want to create a method that removes an item, call it Remove, not Delete. Developers using your class will have an intuitive understanding of what Remove does because they’re familiar with

157

Chapter 5

it. On the other hand, developers would do a double-take on seeing Delete, because that term has a different connotation.

One of the problems with using an ArrayList is that the developer who has an array list cannot guarantee that every item in the list is of the same type. For this reason, each time an item is extracted from the ArrayList, the type should be checked to avoid causing an error.

The solution is to create a strongly typed collection, which contains only elements of a particular type. Strongly typed collections are very easy to create. According to .NET best programming practices as defined by Microsoft, the best way to create one is to derive a new class from System.Collections. CollectionBase (discussed in the How It Works for the next Try It Out) and add two methods (Add and Remove) and one property (Item):

Add adds a new item to the collection.

Remove removes an item from the collection.

Item returns the item at the given index in the collection.

Creating CustomerCollection

In this Try It Out, you create a CustomerCollection designed to hold a collection of Customer structures.

Try It Out

Creating CustomerCollection

1.In the Solution Explorer, right-click the project and choose Add from the context menu and then choose the Class submenu item. In the Add New Item – Structure Demo dialog box, enter CustomerCollection in the Name field and then click the Add button to have the class added to your project.

2.Add the following highlighted line in the Code Editor:

Public Class CustomerCollection

Inherits Collections.CollectionBase

End Class

3.You’ll need to add an Add method to add a customer to the collection. Add the following code:

‘Add a customer to the collection

Public Sub Add(ByVal newCustomer As Customer)

Me.List.Add(newCustomer)

End Sub

4.You need to add a Remove method to remove a customer from the collection, so add this method:

‘Remove a customer from the collection

Public Sub Remove(ByVal oldCustomer As Customer)

Me.List.Remove(oldCustomer)

End Sub

158

Working with Data Structures

5.Open the Code Editor for the form and find the definition for the objCustomers member. Change its type from ArrayList to CustomerCollection as highlighted here:

Public Class Form1

‘Form level members

Private objCustomers As New CustomerCollection

6.Finally, run the project. You’ll notice that the application works as before.

How It Works

Your CustomerCollection is the first occasion for you to create a class explicitly (although you have been using them implicitly from the beginning). Classes and objects are discussed in Chapter 10 and thereafter. For now, note that, like a structure, a class represents a data type that groups one or more members that can be of different data types, and it can have properties and methods associated with it. Unlike a structure, a class can be derived from another class, in which case it inherits the members, properties, and methods of that other class (which is known as the base class) and can have further members, properties, and methods of its own.

Your CustomerCollection class inherits from the Collections.CollectionBase class, which contains a basic implementation of a collection that can hold any object. In that respect it’s very similar to an ArrayList. The advantage comes when you add your own methods to this class.

Since you provided a version of the Add method that has a parameter type of Customer, it can accept and add only a Customer structure. Therefore, it’s impossible to put anything into the collection that isn’t a Customer. You can see there that IntelliSense is telling you that the only thing you can pass through to Add is a Structure_Demo.Customer structure.

Internally, CollectionBase provides you with a property called List, which in turn has Add and Remove methods that you can use to store items. That’s precisely what you use when you need to add or remove items from the list:

‘Add a customer to the collection

Public Sub Add(ByVal newCustomer As Customer) Me.List.Add(newCustomer)

End Sub

‘Remove a customer from the collection

Public Sub Remove(ByVal oldCustomer As Customer) Me.List.Remove(oldCustomer)

End Sub

Building collections this way is a .NET best practice. As a newcomer to .NET programming, you may not appreciate just how useful this is, but trust us — it is! Whenever you need to use a collection of classes, this technique is the right way to go and one that you’ll be familiar with.

Adding an Item Property

At the beginning of this section, you read that you were supposed to add two methods and one property. You’ve seen the methods but not the property, so take a look at it in the next Try It Out.

159

Chapter 5

Try It Out

Adding an Item Property

1.Open the Code Editor for CustomerCollection and add this code:

‘Item property to read or update a customer at a given position ‘in the list

Default Public Property Item(ByVal index As Integer) As Customer Get

Return Me.List.Item(index)

End Get

Set(ByVal value As Customer)

Me.List.Item(index) = value

End Set

End Property

2.To verify that this works, open the Code Editor for Form1. Modify the SelectedCustomer property with this code:

If lstCustomers.SelectedIndex <> -1 Then ‘Return the selected customer

Return objCustomers(lstCustomers.SelectedIndex)

End If

3.Run the project. Click the Test button and notice that when you select items in the list, the details are shown in the fields as they were before.

How It Works

The Item property is actually very important; it gives the developer direct access to the data stored in the list but maintains the strongly typed nature of the collection.

If you look at the code again for SelectedCustomer, you’ll notice that when you wanted to return the given item from within objCustomers, you didn’t have to provide the property name of Item. Instead, objCustomers behaved as if it were an array:

If lstCustomers.SelectedIndex <> -1 Then ‘Return the selected customer

Return objCustomers(lstCustomers.SelectedIndex) End If

IntelliSense tells you to enter the index of the item that you require and that you should expect to get a Customer structure in return.

The reason you don’t have to specify the property name of Item is that you marked the property as default by using the Default keyword:

‘Item property to read or update a customer at a given position ‘in the list

Default Public Property Item(ByVal index As Integer) As Customer Get

Return Me.List.Item(index) End Get

160

Working with Data Structures

Set(ByVal value As Customer)

Me.List.Item(index) = value

End Set

End Property

A given class can only have a single default property, and that property must take a parameter of some kind. This parameter must be an index or search term of some description. The one used here provides an index to an element in a collection list. You can have multiple overloaded versions of the same property so that, for example, you could provide an e-mail address rather than an index. This provides a great deal of flexibility to enhance your class further.

What you have at this point is the following:

A way of storing a list of Customer structures, and just Customer structures

A way of adding new items to the collection on demand

A way of removing existing items from the collection on demand

A way of accessing members in the collection as if it were an ArrayList

Building Lookup Tables with Hashtable

So far, whenever you want to find something in an array or in a collection, you have to provide an integer index representing the position of the item. It’s quite common to end up needing a way of being able to look up an item in a collection when you have something other than an index. For example, you might want to find a customer when you provide an email address.

In this section you’ll take a look at the Hashtable. This is a special kind of collection that works on a key-value principle.

Using Hashtables

A Hashtable is a collection in which each item is given a key. This key can be used at a later time to “unlock” the value. So, if you add Darrel’s Customer structure to the Hashtable, you’ll be given a key that matches his e-mail address of dhilton@somecompany.com. If at a later time you come along with that key, you’ll be able to find his record quickly.

Whenever you add an object to the Hashtable, it calls a method System.Object.GetHashCode, which provides a unique integer value for that object that is the same every time it is called, and uses this integer ID as the key. Likewise, whenever you want to retrieve an object from the Hashtable, it calls GetHashCode on the object to get a lookup key and matches that key against the ones it has in the list. When it finds it, it will return the related value to you.

Lookups from a Hashtable are very, very fast. Irrespective of the object you pass in, you’re only matching on a relatively small integer ID. You learn to use a Hashtable in the following Try It Out.

An integer ID takes up 4 bytes of memory, so if you pass in a 100-character string (which is 200-bytes long), the lookup code only needs to compare 4 bytes, which makes everything run really quickly.

161

Chapter 5

Try It Out

Using a Hashtable

1.Open the Code Editor for the CustomerCollection class. Add the highlighted member to the top of the class definition:

Public Class CustomerCollection

Inherits Collections.CollectionBase

‘Private member

Private objEmailHashtable As New Hashtable

2.Next, add this read-only property to the class:

‘EmailHashtable property to return the Email Hashtable Public ReadOnly Property EmailHashtable() As Hashtable

Get

Return objEmailHashtable

End Get

End Property

3.Now, make this change to the Add method:

‘Add a customer to the collection

Public Sub Add(ByVal newCustomer As Customer) Me.List.Add(newCustomer)

‘Add the email address to the Hashtable EmailHashtable.Add(newCustomer.Email, newCustomer)

End Sub

4.Next, add this overloaded version of the Item property that allows you to find a customer by email address:

‘Overload Item property to find a customer by email address

Default Public ReadOnly Property Item(ByVal email As String) As Customer Get

Return EmailHashtable.Item(email)

End Get

End Property

5.Open the Form Designer for Form1, resize the Email text box smaller, and add a new Button control next to it as shown in Figure 5-20. Set the Name property of the button to btnLookup and the Text property to Lookup.

6.Double-click the Lookup button and add the following highlighted code to its Click event handler:

Private Sub btnLookup_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnLookup.Click

162

Working with Data Structures

Figure 5-20

‘Declare a customer object and set it to the customer ‘with the email address to be found

Dim objFoundCustomer As Customer = objCustomers(txtEmail.Text)

If objFoundCustomer.Email IsNot Nothing Then ‘Display the customers name

MessageBox.Show(“The customers name is: “ & objFoundCustomer.Name, _ “Structure Demo”)

Else

‘Display an error

MessageBox.Show(“There is no customer with the e-mail address “ & _ txtEmail.Text & “.”, “Structure Demo”)

End If End Sub

7.Run the project and click the Test button to populate the list of customers. If you enter an email address that does not exist into the Email text box and click the Lookup button, you’ll see a message box similar to the one shown in Figure 5-21.

Figure 5-21

8.If you enter an email address that does exist, for example, dhilton@somecompany.com, the name of the customer will be shown in the message box.

163

Chapter 5

How It Works

You’ve added a new member to the CustomerCollection class that can be used to hold a Hashtable:

‘Private member

Private objEmailHashtable As New Hashtable

Whenever you add a new Customer to the collection, you also add it to the Hashtable:

‘Add a customer to the collection

Public Sub Add(ByVal newCustomer As Customer) Me.List.Add(newCustomer)

‘Add the email address to the Hashtable EmailHashtable.Add(newCustomer.Email, newCustomer)

End Sub

However, unlike the kinds of Add methods that you saw earlier, the EmailHashtable.Add method takes two parameters. The first is the key, and you’re using the email address as the key. The key can be any object you like, but it must be unique. You cannot supply the same key twice. (If you try to, an exception will be thrown.) The second parameter is the value that you want to link the key to, so whenever we give that key to the Hashtable, you get that object back.

The next trick is to create an overloaded version of the default Item property. This one, however, takes a string as its only parameter. IntelliSense will display the overloaded method as items 1 and 2 when you access it from your code.

This time you can provide either an index or an email address. If you use an email address, you end up using the overloaded version of the Item property, and this defers to the Item property of the Hashtable object. This takes a key and returns the related item, providing the key can be found:

‘Overload Item property to find a customer by email address

Default Public ReadOnly Property Item(ByVal email As String) As Customer Get

Return EmailHashtable.Item(email) End Get

End Property

So, at this point, you have a collection class that not only enables you to look up items by index but also allows you to look up customers by email address.

Cleaning Up: Remove, RemoveAt, and Clear

It isn’t possible to use the same key twice in a Hashtable. Therefore, you have to take steps to ensure that what’s in the Hashtable matches whatever is in the list itself.

Although you implemented the Remove method in your CustomerCollection class, the Collection Base class also provides the RemoveAt and Clear methods. Whereas Remove takes an object, RemoveAt takes an index. In the next Try It Out, you need to provide new implementations of these methods to adjust the Hashtable.

164

Working with Data Structures

Try It Out

Cleaning Up the List

1.Open the Code Editor for Form1. Locate the btnTest_Click method and add the highlighted code to clear the two lists:

Private Sub btnTest_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnTest.Click

‘Clear the lists objCustomers.Clear() lstCustomers.Items.Clear()

‘Create some customers

CreateCustomer(“Darrel”, “Hilton”, “dhilton@somecompany.com”) CreateCustomer(“Frank”, “Peoples”, “fpeoples@somecompany.com”) CreateCustomer(“Bill”, “Scott”, “bscott@somecompany.com”)

End Sub

2.To demonstrate how a Hashtable cannot use the same key twice, run your project and click the Test button to have the customer list loaded. Now click the Test button again and you’ll see the error message shown in Figure 5-22:

Figure 5-22

3.Click the Stop Debugging button on the toolbar in Visual Studio 2005 to stop the program.

4.Now add the following method to the CustomerCollection class:

‘Provide a new implementation of the Clear method Public Shadows Sub Clear()

‘Clear the CollectionBase MyBase.Clear()

‘Clear your hashtable EmailHashtable.Clear()

End Sub

165