Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Object Binding Tips and Tricks : Page 4

Visual Studio 2005 and the .NET Framework 2.0 greatly enhance the data binding story in Windows Forms. This article explores the classes, interfaces, and coding techniques you can use today in your Windows Forms applications.


advertisement
Managing Lists
There are frequently times when you need lists of things in the user interface of your application. For example, you may want to display all of the customers in a combo box for the user to select the customer to edit. You may want to provide a list of customer types, states, or payment plans. Or you may want to display a list of all products that the customer has purchased in a grid.

Let's look first at how to implement a reasonably-sized list of items where you need to display and possibly edit a number of the properties of the item. The example mentioned above was to display a list of the items that a customer purchased in a grid.

To begin the implementation, add a PurchasedItem class to your project and give it suitable properties such as ItemName, Description, and ItemID. Implement a Create method similar to the Create method for the Customer class, but this time allow passing in of a DataRow instead of an ID. (For the implementation of this class, downloadable code for this article.)

Add a PurchasedItemCollection class to your project and inherit this class from BindingList(Of T). Note that the BindingList generic collection is located in System.ComponentModel.

In VB:

Public Class PurchasedItemCollection Inherits BindingList(Of PurchasedItem)

In C#:

class PurchasedItemCollection : BindingList<PurchasedItem>

Following the factory pattern, implement a Create method that will create the collection entries.

In VB:



Public Shared Function Create(ByVal CustomerID _ As Int32) As PurchasedItemCollection Dim oCollection As New PurchasedItemCollection Dim dt As DataTable ' Perform the appropriate retrieve dt = oCollection.Retrieve(CustomerID) ' For each row, create an object in the list For Each dr As DataRow In dt.Rows Dim oItem As PurchasedItem oItem = PurchasedItem.Create(dr) oCollection.Add(oItem) Next Return oCollection End Function

In C#:

public static PurchasedItemCollection Create( Int32 CustomerID) { PurchasedItemCollection oCollection = new PurchasedItemCollection(); // Perform the appropriate retrieve DataTable dt = oCollection.Retrieve(CustomerID); // For each row, create an object in the list foreach (DataRow dr in dt.Rows) { PurchasedItem oItem = PurchasedItem.Create(dr); oCollection.Add(oItem); } return oCollection; }

Add a Retrieve method similar to the Customer Retrieve method. (For the implementation of this method, see the downloadable code for this article.)

When the implementation of both classes is complete, build the project to ensure that the new classes are accessible to the Data Sources window. Then create a data source for the PurchasedItemCollection class following the same steps as for the Customer class. Ensure that you've set the DataGridView as the default and then drag the PurchasedItemCollection data source and drop it onto the bottom of the form. A grid should appear with a column for each property defined in the PurchasedItem class.

In the form's Load event, set the DataSource for the PurchasedItemCollectionBindingSource to an instance of the PurchasedItemCollection class.

In VB:

Private Sub CustomerWin_Load(ByVal sender As _ Object, ByVal e As System.EventArgs) _ Handles Me.Load Dim CustomerInstance As Customer CustomerInstance = Customer.Create(1) CustomerBindingSource.DataSource = _ CustomerInstance Dim ItemCollection As PurchasedItemCollection ItemCollection = _ PurchasedItemCollection.Create(1) PurchasedItemCollectionBindingSource. _ DataSource = ItemCollection End Sub

In C#:

private void CustomerWin_Load(object sender, EventArgs e) { Customer CustomerInstance = Customer.Create(1); customerBindingSource.DataSource = CustomerInstance; PurchasedItemCollection ItemCollection = PurchasedItemCollection.Create(1); purchasedItemCollectionBindingSource. DataSource = ItemCollection; }

Object binding to a class that inherits from BindingList(Of T) provides a very nice way to display and manage lists of things. However, notice that it creates and populates an instance for every item in the list. That is not a problem when you have a reasonable set of items, like in this example. But it may not perform well if you have hundreds of thousands of items in the list.

When you need large read-only lists of key values, such as a list of customer names from which the user can select a customer to edit, it does not seem efficient to create an instance for each one. In this case, you may want to bind directly to a DataTable of key values. But with a little trick, you can still have the illusion of object binding in this case.

Add a CustomerList class to your project and give it properties that match the names of the key values, for example, CustomerID and FullName. Also give it a CustomerDataTable property that returns the DataTable of key values. Finally, implement a Retrieve method to retrieve the DataTable. The resulting code is shown in Listing 3 and Listing 4.

Build the project and create a data source for the CustomerList class. In the Data Sources window, set the FullName property to display as a combo box. Then drag the FullName property onto the form. Figure 2 shows the results that should appear.

 
Figure 2: The combo box provides for more complex data binding.
Click on the smart tag of the combo box to set the combo box properties. Set the DisplayMember to FullName and the ValueMember to CustomerID.

Finally, modify the user interface to populate the combo box and then to populate the other controls when the user selects the customer from the combo box. (Be sure to comment out or delete the Load event code created earlier.)

In VB:

Private Sub CustomerWin_Load(ByVal sender As _ Object, ByVal e As System.EventArgs) _ Handles Me.Load ' Bind the list Dim oList As New CustomerList CustomerListBindingSource.DataSource = _ oList.CustomerDataTable End Sub Private Sub _ FullNameComboBox_SelectionChangeCommitted( _ ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles FullNameComboBox.SelectionChangeCommitted Dim oCustomer As Customer oCustomer = Customer.Create( FullNameComboBox.SelectedValue) CustomerBindingSource.DataSource = oCustomer Dim oCollection As PurchasedItemCollection oCollection = PurchasedItemCollection.Create( _ FullNameComboBox.SelectedValue) PurchasedItemCollectionBindingSource. _ DataSource = oCollection End Sub

In C#:

private void CustomerWin_Load(object sender, EventArgs e) { CustomerList oList = new CustomerList(); customerListBindingSource.DataSource = oList.CustomerDataTable; } private void fullNameComboBox_SelectionChangeCommitted( object sender, EventArgs e) { Int32 selectedID = Convert.ToInt32( fullNameComboBox.SelectedValue); Customer oCustomer = Customer.Create(selectedID); customerBindingSource.DataSource = oCustomer; PurchasedItemCollection oCollection = PurchasedItemCollection.Create(selectedID); purchasedItemCollectionBindingSource. DataSource = oCollection; }

This basically fakes the object binding into thinking that it is binding to an object when in reality it is binding to a DataTable. This technique is very useful any time that you don't need instances of the class but want to standardize all of your data sources to use object binding. (If you don't mind mixed data sources, you could bind directly to a TableAdapter using Database binding instead of "fake" object binding here.)

In the Customer example, it makes sense to bind to a DataTable because of the possible large number of customers. And from a work flow perspective; it is highly likely that the user would only edit a few customers at a time-making it wasteful to create hundreds of thousands of individual instances and then bind to the list of these instances.

You can also use this fake object binding technique in cases where you need a list of types such as customer types, states, payment plans, and so on. In these cases the lists will always be read-only so there is no real need to create and manage instances.

As an example, add a State property to the Customer class. Build the project and you will notice that the State is added to the Data Sources window. Then build a StateList class similar to the CustomerList class created in this article. This StateList class will manage the list of states.

When using lists such as these, there are three properties of the combo box that you need to work with, all accessible from the combo box smart tag:

  • DisplayMember. Property you would like displayed in the combo box, such as "StateName." This should be a property of your StateList class.
  • ValueMember. Property you would like used as the value of the combo box selection, such as "StateID." This should also be a property of your StateList class.
  • SelectedValue. Binding source and property to which the user-selected value should be assigned. This should be a property of the Customer class, such as "State" and therefore a property of the CustomerBindingList.
This gives you full-featured object binding without needing to create classes and instances for all of your type codes.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap