|
Table of Contents
- Page 1
- Introduction
- Smart Data vs. Raw Data
- Smart DataTables
- RAD Support for Objects
- Page 2
- Data Binding a Form to an Object
- Data Binding a Form to a Collection
- Page 3
- Conclusion
- About the Author
- Listing 1
- Listing 2
Introduction
I'm often asked whether it is better to use a DataSet, a strongly typed DataSet or business objects to implement applications. My view on this topic is strongly in favor of business objects today, and I expect it to remain so as we look forward to Visual Studio 2005 and .NET 2.0.
Though I am a strong advocate of object-oriented programming and the use of business objects, it is important to note that .NET 2.0 will have some important new DataTable features that make the concept of a strongly typed DataTable very interesting in the future. Unfortunately, using strongly typed DataSets today doesn't really help prepare you for these new features.
I'll briefly discuss the new smart DataTable technology before moving on to discuss what I'm really excited about, which is the new object data binding capabilities in Windows Forms.
Smart Data vs. Raw Data
I basically divide software into two groups -- data-centric and object-oriented. More broadly you might consider these as 'raw data' and 'smart data'.
By 'raw data', I am referring to the fact that a DataSet, DataTable, XML document, two-dimensional array or other basic data container has no intrinsic business intelligence. Sure, some of the containers can do basic things like ensuring that a numeric column only contains numbers, but it can't make sure they are good numbers. In short, there's no way to embed business logic in a dumb data container.
The result is that the data is used and manipulated by external code (typically in the UI), and we have no guarantee that our business rules (validation, manipulation, authorization) are properly followed. Hopefully the UI code properly and consistently applies all business rules, but there's no systematic way to know for sure.
Contrast this with a 'smart data' approach, which is typically implemented with business objects. In this case the data is in a container that implements all the business rules (validation, manipulation, authorization). The only way to interact with the data is through the smart data container, thus ensuring that all business logic is systematically applied to the data.
In this case we can have a high degree of confidence that business logic is consistently and reliably applied to our data, regardless of what kind of code is in the UI.
Smart DataTables
In .NET 2.0 we're getting a new feature, which I've personally dubbed the 'smart DataTable'. I'm sure Microsoft will have a cool marketing name for it at some point, but for now this is the term I'm using.
The smart DataTable is a strongly typed DataTable that directly embeds our business logic. This is done using another new feature, partial classes. This is the same feature that is used in .NET 2.0 to embed our custom logic in Windows Forms and Web Forms. In other words, a smart DataTable is, programmatically, just like a form.
To put code in (or behind) a form, we respond to form-based events and write our code in the appropriate event handlers. With smart DataTables, this is what we'll do as well. The smart DataTable will raise events, and we'll write our business logic (validation, manipulation, authorization) in the appropriate event handlers.
The magic here is that the smart DataTable code and our business code are combined together at compile time (via partial class technology) into a single class. The end result is that client code (typically UI code) will be unable to create a DataTable that doesn't have our business logic embedded inside.
This means that a smart DataTable, like a business object, effectively wraps the data within a cocoon of business logic. The only way to interact with the data is through the smart container (business object or smart DataTable), and thus we are guaranteed that our business logic will be consistently and reliably applied against the data.
The primary drawbacks to this approach are that the business logic is only per-DataTable and that our view of the data remains fundamentally relational, not object-oriented.
The fact that our logic can be embedded within the DataTable is very good because it encapsulates the logic and data within the same entity. Unfortunately, there's no provision for logic in one DataTable to interact with other DataTable objects. This can make it difficult to implement logic in an Invoice DataTable that recalculates the total amount based on the values in a LineItems DataTable.
There are no events or other mechanisms that help link related DataTable objects together. While we can implement such mechanisms on our own within our partial class code, the lack of pre-existing support is unfortunate.
The bigger issue, in my mind, is that even smart DataTables still provide a view of data that is fundamentally rooted in the relational world, not the object-oriented world. I believe that there are tremendous benefits to proper use of object-oriented design and programming. These benefits include creation of systems and code that are self-documenting, easier to maintain, and that are more adaptable to changing business needs over time.
For small, or simple applications, the smart DataTable is a wonderful tool. It provides some very important encapsulation functionality for our logic and data. However, for most complex applications we need a more powerful way of expressing the concepts and entities that make up the application, and then object-oriented design and programming are the more appropriate choice.
RAD Support for Objects
One of the primary arguments against object-oriented programming for business applications has been the lack of decent rapid application development (RAD) support for objects. The development tools (such as Visual Studio, Powerbuilder and others) we've been using had excellent RAD support for a data-centric development model, but little to no RAD support for the object-oriented developer.
This started changing with Visual Studio .NET 2002 and 2003, where at least it was possible to employ data binding against business objects when building Windows Forms or Web Forms user interfaces. Even so, Visual Studio .NET didn't provide any graphical way to set up the data binding between controls and objects. We were left to do the binding work ourselves, through code. This led to a lot of Windows Forms code that looks like this:
txtName.DataBindings.Add("Text", mCustomer, "Name")
txtCity.DataBindings.Add("Text", mCustomer, "City")
txtState.DataBindings.Add("Text", mCustomer, "State")
This was far better than manually loading the data into the controls and handling the LostFocus or Changed events to put the data from the control back into the object. However, it was still a far cry from the graphical RAD capabilities offered by Visual Studio .NET when using a DataSet or DataTable.
In Visual Studio 2005, however, object-oriented developers are slated to get a whole new set of RAD capabilities. The end result is that we'll get the same basic RAD experience regardless of whether we're using a DataTable or a custom business object.
Let's explore this support a bit. But first I want to be clear that we are working with pre-beta software. Everything in this article is subject to change. While the basic features and concepts are likely to remain reasonably consistent, there's no guarantee. In any case, some of the details and the appearance of the UI components in Visual Studio 2005 will almost certainly change between now and the product's release.
In this article I'll be focusing on Windows Forms data binding and how it works with objects. This is quite different from Web Forms data binding, which is improved in Visual Studio 2005, but is still not as powerful or flexible as Windows Forms data binding.
Windows Forms data binding doesn't impose any serious restrictions on how we build our objects. Objects are not required to have a default constructor or to implement any interfaces or specific methods. The only real requirement is that objects expose data through properties, so data binding can bind the properties to our controls.
In Web Forms there are numerous restrictions on our objects. Most notably, the entire design is stateless. Objects must have a default constructor, and they must implement specific stateless, atomic methods for data retrieval, insert, update and deletion. The result is not a typical business object, but rather is an object that merely houses a set of four CRUD (create, read, update, delete) commands. These objects are more like an ADO.NET DataAdapter than they are like a DataTable.
Again, in this article I'm going to focus on Windows Forms data binding and how it works with business objects. To start with, let's look at a basic business class that represents a Product. Following the basic pattern I use for objects in my Expert One-on-One VB.NET Business Objects and Expert C# Business Objects books, this class has a Shared (static in C#) factory method to create and initialize an object. It also has a Private constructor to force users of the class to employ the NewProduct factory method:
Imports System.ComponentModel
Public Class Product
Implements IPropertyChange
Public Event PropertyChanged(ByVal sender As Object, _
ByVal e As PropertyChangedEventArgs) _
Implements IPropertyChange.PropertyChanged
Private mName As String = ""
Private mPrice As Single
Private Sub New()
' require use of factory method
End Sub
Public Shared Function NewProduct( _
ByVal name As String, ByVal price As Single) As Product
Dim prod As New Product
prod.Name = name
prod.Price = price
Return prod
End Function
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
RaiseEvent PropertyChanged( _
Me, New PropertyChangedEventArgs("Name"))
End Set
End Property
Public Property Price() As Single
Get
Return mPrice
End Get
Set(ByVal value As Single)
mPrice = value
RaiseEvent PropertyChanged( _
Me, New PropertyChangedEventArgs("Price"))
End Set
End Property
End Class
This class doesn't implement any data access. Normally a business object will store its data in a relational database such as SQL Server.
The reason I am avoiding data access here is because I want to keep the discussion focused on the new data binding capabilities in Windows Forms, rather than on issues around the design of business objects and how to map object data into a relational data store. In my Expert One-on-One VB.NET Business Objects and Expert C# Business Objects books I devote substantial time to discussing object persistence and object-relational mapping (ORM) concepts. For the purposes of data binding, however, all we really need is an object that has some properties to which our controls can be bound.
Notice that the Product class implements the new System.ComponentModel.IPropertyChange interface. This interface allows objects to notify the data binding infrastructure when a property value is changed. Compared to the late-bound propertyChanged event concept in .NET 1.x, this is a tremendous benefit. The IPropertyChange interface provides a very clear and easy to implement way for our objects to indicate when a property value has changed. Notice how each Set block raises the event:
Set(ByVal value As Single)
mPrice = value
RaiseEvent PropertyChanged( _
Me, New PropertyChangedEventArgs("Price"))
End Set
Beyond this, the Product class is a very simple business class. Let's see how we can use the new Windows Forms data binding to create a form to edit a Product object.
The first thing we need to do is set up a data source within our project. This is the first step in Visual Studio 2005 regardless of whether we are using DataTable objects, business objects, or Web services. Adding a data source is done through a wizard, which is invoked by selecting the Data|Show Data Sources menu option as shown in Figure 1.

Figure 1. Choosing the Data|Show Data Sources menu option.
In a new project this menu option will bring up the wizard. If we already have a data source in our project, this menu option brings up the Data Sources window. In that case, to bring up the wizard, click the Add New Data Source icon in the window's toolbar.
The first thing the wizard needs to know is what type of data source we're trying to add. The options are shown in Figure 2.

Figure 2. Choosing the type of data source to add.
In our case, we're interested in adding the Product class as a data source, so we'll choose the Object option. This causes the wizard to examine our current project and referenced assemblies for classes.
It is important to note that we must compile our assembly before this will work. If we haven't compiled our project, the wizard will be unable to find our classes. This is because the wizard is using reflection to scan the assembly for information about our classes, their properties and so forth.
A summary of the data source options are listed in Table 1.
Table 1. Summary of data sources available through the wizard.
|
Data Source
|
Description
|
|
Database
|
Provides an ADO.NET DataTable or DataSet connected to a
relational database such as SQL Server
|
|
Local Database File
|
Provides an ADO.NET DataTable or DataSet connected to a
local database file (such as an Access database)
|
|
Web Service
|
Provides a class describing the result returned from a Web
Service; this class is generated from the WSDL describing the service
|
|
Object
|
Uses a class from our project or an assembly referenced by
our project
|
When we choose the Object option and click Next, the resulting display of classes will look similar to that in Figure 3. Notice how the Product class is listed as an option.

Figure 3. Selecting a data source from a list of classes.
If we select Product and finish the wizard, the Data Sources window will display our class as a data source. You can see the result in Figure 4.

Figure 4. The Product class as a data source for our project.
At this point we can use RAD concepts, such as drag-and-drop, to create a form to edit Product objects. To do this, we have several options:
- We can drag the entire Product class from the Data Sources window onto a form
- We can drag individual properties from the Data Sources window onto a form
- We can drag individual properties from the Data Sources window onto existing controls on a form
In our case, we'll stick with option 1, since we're planning to create a form to edit the entire Product object.
Data Binding a Form to an Object >>
|