In a number of projects, an application is broken up into multiple tiers. Quite often it is not possible to pass around strongly typed DataSets, because they may be quite large, or perhaps the project requires custom business objects. In either case, it is possible to take the DataBinding techniques you just learned for DataSets and apply them to objects. For the purposes of this discussion, use the following Customer and SalesOrder classes:
Public Class Customer Private m_Name As String Public Property Name() As String Get Return m_Name End Get Set(ByVal value As String) m_Name = value End Set End Property Private m_Orders As New List(Of SalesOrder) Public Property Orders() As List(Of SalesOrder) Get Return m_Orders End Get Set(ByVal value As List(Of SalesOrder)) m_Orders = value End Set End Property End Class
Public Class SalesOrder Implements System.ComponentModel.IDataErrorInfo Private m_Description As String Public Property Description() As String Get Return m_Description End Get Set(ByVal value As String) m_Description = value End Set End Property Private m_Quantity As Integer Public Property Quantity() As Integer Get Return m_Quantity End Get Set(ByVal value As Integer) m_Quantity = value End Set End Property Private m_DateOrdered As Date Public Property DateOrdered() As Date Get Return m_DateOrdered End Get Set(ByVal value As Date) m_DateOrdered = value End Set End Property Public ReadOnly Property ErrorSummary() As String _ Implements System.ComponentModel.IDataErrorInfo.Error Get Dim summary As New System.Text.StringBuilder Dim err As String = ErrorItem("Description") If Not err = "" Then summary.AppendLine(err) err = ErrorItem("Quantity") If Not err = "" Then summary.AppendLine(err) err = ErrorItem("DateOrdered") If Not err = "" Then summary.AppendLine(err) Return summary.ToString End Get End Property Default Public ReadOnly Property ErrorItem(ByVal columnName As String) _ As String Implements System.ComponentModel.IDataErrorInfo.Item Get Select Case columnName Case "Description" If Me.m_Description = "" Then _
Return "Need to order item description" Case "Quantity" If Me.m_Quantity <= 0 Then _ Return "Need to supply quantity of order" Case "DateOrdered" If Me.m_DateOrdered > Now Then _ Return "Need to specify a date in the past" End Select Return "" End Get End Property End Class
To use DataBinding with custom objects, follow roughly the same process as you did with DataSets. Add a new data source via the Data Sources window. This time, select an Object Data Source type. Doing so will display a list of available classes within the solution, as shown in Figure 21-20.
Select the Customer class and complete the wizard to add the Customer class, along with the nested list of orders, to the Data Sources window, as shown in Figure 21-21.
As you did previously, you can select the type of control you want for each of the fields before dragging the Customer node onto the form. Doing so adds a CustomerBindingSource and a CustomerNavigator to the form. If you set the Orders list to be a DataGridView and drag that onto the form, you will end up with the layout shown in Figure 21-22. As you did previously with the DataGridView, again opt to modify the default list of columns using the Edit Columns dialog accessible from the smart tag dialog.
Unlike binding to a DataSet that has a series of TableAdapters to extract data from a database, there is no automatically generated fill mechanism for custom objects. The process of generating the customer objects is usually handled elsewhere in the application. All you have to do here is issue the following code snippet to link the existing list of customers to the CustomerBindingSource so they can be displayed:
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.CustomerBindingSource.DataSource = GetCustomers() End Sub Public Function GetCustomers() As Customer() 'Populate customers list..... eg from webservice Dim cust As Customer() = New Customer() { _ New Customer With {.Name = "Joe Blogs"}, _ New Customer With {.Name = "Sarah Burner"}, _ New Customer With {.Name = "Matt Swift"}, _ New Customer With {.Name = "Barney Jones"}} Return cust End Function
Running this application provides a simple interface for working with customer objects.
You will notice in the code provided earlier that the SalesOrder object implements the IDataErrorInfo interface. This is an interface that is understood by the DataGridView and can be used to validate custom objects. As you did in the earlier application, you need to add an ErrorProvider to the form. Instead of manually wiring up events in the ErrorProvider control, in conjunction with the DataGridView use the IDataErrorInfo interface to validate the SalesOrder objects. The running application is shown in Figure 21-23, where an invalid date and no quantity have been specified for a SalesOrder.
The icon at the end of the row provides a summary of all the errors. This is determined by calling the Error property of the IDataError interface. Each of the columns in turn provides an icon to indicate which cells are in error. This is determined by calling the Item property of the IDataError interface.
18.118.198.81