1. Building Data-Bound Applications with Windows Forms

It is almost impossible to design a significant application without dealing with data in some form. If the application is a simple arcade game, the data may be a log of past scores or configuration data that lets a user customize the way the application behaves. If the application is a graphical design tool, the data may be a complex graph of objects that need to be manipulated by the application and by the user and saved when the application or document is closed. If the application is a high-end enterprise business application, the data might be an aggregation of complex relational data residing in multiple distributed databases, objects, and files used in the processing that the application performs.

To build any of these kinds of applications, you need a good way to store the data, load it, and manipulate it. If the data will be exposed directly to the user through a presentation tier application, you need intuitive ways to present the data and let the user interact with it. Most of this book is focused on just that—providing rich data presentation and interaction for users of your Windows Forms applications. However, there is a lot more to building a good data-bound application than just the presentation aspects. This chapter not only introduces the key concepts of data binding, it also tries to paint the picture of the bigger context in which your Windows Forms application lives.

What Is Data Binding?

Data binding is a solution to a problem that developers used to solve over and over in user-interface applications. In the past, if you wanted to present data to a user, you had to retrieve the data from where it was stored and get it into your application. You then had to write custom code to render the data with graphics, or you could manually populate properties on controls with the data to display it. The way that you approached this would be different for each situation, each type of data, and each type of presentation that you provided. If the user was allowed to interact with the data and make modifications or additions to it through the user interface, you had to write custom code to collect the modified values from the user interface and push them back into the underlying data objects or collections in memory. You also needed code that persisted the changed values to the data store from which it came. This required a lot of repetitive and error-prone code, which always cries out for a better solution. Figure 1.1 depicts this process.

FIGURE 1.1: Data-Binding Process

Data-Binding Process

Data binding encapsulates all of these steps into components that help present the data, which reduces the amount of code that you need to write. Some of that code goes into the data-bound controls that present the data, and some of it goes into nonvisual components that make data binding easier (this is described in detail in Chapters 79).

Data binding also involves providing easy-to-understand patterns for how you write code to hook up data to controls for presentation and editing. Finally, it involves developer tools that help write the code for you, using intuitive design-time interactions provided by Visual Studio 2005. The overall process of presenting and editing data is still basically the same as when no data binding is involved, but using data binding significantly reduces the amount and complexity of the code you have to write.

Data binding has been around in various forms in different environments since early versions of tools like Visual Basic, FoxPro, and Delphi. Many early attempts at data binding left a lot to be desired—they either exposed too many details to the programmer, provided inconsistent or unreliable behavior to the user, or were just too complicated to use and understand. Data-binding capabilities have been part of the .NET Framework for both Windows Forms and ASP.NET Web forms since version 1.0 of each. The data-binding capabilities of Windows Forms controls in .NET 1.0 and 1.1 were a big improvement over previous environments, but they still fell short in many situations. Significant improvements have been made in Windows Forms 2.0, making it both quicker and easier to get data-bound applications up and running.

Your First Data-Bound Windows Forms 2.0 Application

To get your hands dirty early with Windows Forms 2.0 and Visual Studio 2005, the following procedures give a quick demonstration of their easy and powerful new capabilities. You can either follow along if you have a machine with Visual Studio 2005 handy or just use the figures to visualize the process. You will:

1.   Create a Windows application project

2.   Add a new data source and a data connection

3.   Select data objects

4.   Customize data sources control mappings

5.   Generate data-bound controls

6.   Run an application

Don’t worry about understanding all of the steps at this point; they will be described in detail in later chapters.

Creating a Windows Application Project

1.   Start Visual Studio 2005. You’ll see the Start Page (shown in Figure 1.2). Click Create to display the New Project dialog. If you don’t see the Start Page, select File > New > Project from the menu.

FIGURE 1.2: Visual Studio Start Page

Visual Studio Start Page

2.   In the New Project dialog (see Figure 1.3), expand the Visual C# option under Project types, and select the Windows Application template.

FIGURE 1.3: New Project Dialog

New Project Dialog

3.   Name the project FirstDataApp, select a working directory for the application in the Location field, and click OK.

At this point, you will have an open Windows Forms project with the default Form1 class displayed in the designer (see Figure 1.4).

FIGURE 1.4: Empty Windows Forms Project

Empty Windows Forms Project

Adding a New Data Source and a Data Connection

1.   From the Data menu, select Add New Data Source. This displays the Data Source Configuration wizard (see Figure 1.5).

FIGURE 1.5: Source Selection in the Data Source Configuration Wizard

Source Selection in the Data Source Configuration Wizard

2.   Select Database as the data source type and click Next. This displays a page to set your data connection (see Figure 1.6).

FIGURE 1.6: Data Source Configuration Wizard Connection Selection

Data Source Configuration Wizard Connection Selection

     Select the data connection that you want to use. The options available depend on whether you have previously configured data connections in Visual Studio 2005. Assuming that you haven’t configured a connection to the Northwind database yet, you will need to add a new connection. If you have already set up data connections in Visual Studio 2005, continue with step 7.

3.   Click the New Connection button. The first time you do this in Visual Studio 2005, the dialog shown in Figure 1.7 is displayed so you can select a data source provider.

FIGURE 1.7: Data Source Provider Selection

Data Source Provider Selection

4.   Under Data source, select Microsoft SQL Server. The option under Data provider defaults to .NET Framework Provider for SQL Server. Click OK.

5.   In the Add Connection dialog (see Figure 1.8), enter localhost as the server name (if you are working with a local default instance of SQL Server 2000 or 2005 with Northwind on it). If you need help getting a database set up, are working with a nondefault instance, or need to work with SQL Server 2005 Express instead, see the book’s Web site for instructions.

FIGURE 1.8: Add Connection Dialog

Add Connection Dialog

6.   Select Use Windows Authentication, enter Northwind as the database, and click OK.

7.   This redisplays the connection selection step of the Data Source Configuration wizard (Figure 1.6). Click Next. The page in Figure 1.9 is displayed.

FIGURE 1.9: Saving the Connection String

Saving the Connection String

8.   To save the connection string information to the application configuration file, accept the default and click Next.

Selecting Data Objects

The last page of the Data Source Configuration wizard (Figure 1.10) displays a tree of the database objects contained in the database (in this case, the Northwind database) you selected in the connection step. This includes tables, views, stored procedures, and functions for a SQL Server database.

FIGURE 1.10: Database Object Selection

Database Object Selection

1.   Expand the Tables node and select the Employees table.

2.   Leave the data set name at the bottom as NorthwindDataSet and click Finish.

By completing this simple wizard, the designer generates approximately 2,000 lines of well-tuned data access code and data type definitions for you.

Customizing Data Sources Control Mappings

This procedure customizes the data source control mappings in Visual Studio.

1.   Open the Data Sources window by selecting Data > Show Data Sources.

2.   Expand the tree of data sources at the Employees level. This shows the tree of controls that can be generated automatically for data binding.

3.   Click on the drop-down arrow next to Photo and select PictureBox as the kind of bound control to be generated (see Figure 1.11).

FIGURE 1.11: Changing the Bound Control Type for the Photo Field

Changing the Bound Control Type for the Photo Field

4.   Click on the drop-down arrow next to the Employees table at the top of the tree, changing its bound control type to Details (see Figure 1.12).

FIGURE 1.12: Changing the Bound Control Type for the Employees Table

Changing the Bound Control Type for the Employees Table

Generating Data-Bound Controls

Now you are ready to generate some data-bound controls on the form.

1.   Left-click and hold on the Employees node in the Data Sources tree, drag it onto the upper left part of the form, about a half-inch down from the title bar, and release the mouse button.

–   The Visual Studio designer generates an entire form with appropriate bound controls for each column in the Employees table. It also generates a Label control next to each data-bound control based on the name of the column, and even does intelligent things with the label such as breaking up the EmployeeID column name into a label whose Text property is set to Employee ID:. The designer also names each of the controls, so instead of getting controls named TextBox1, TextBox2, and so on like you do when you drag controls out from the Toolbox, the designer identifies them with names like employeeIDTextBox and lastNameTextBox.

–   An instance of the NorthwindDataSet class is added to the form as a member, along with a table adapter, which is an instance of the EmployeesTableAdapter that was generated in the section Selecting Data Objects. The table adapter fills the data set and persists changes from it back into the database.

–   A BindingSource component, which is used to tie the data source to the bound controls, is added.

–   A BindingNavigator is also added. This provides navigation controls at the top of the form. These let you page through the records in the table one at a time, add new records, save changes to the records, or delete records.

–   All the code is written behind the scenes to hook up the data-binding properties of the components generated, as well as code to retrieve the contents of the Employees table from the database into the data set instance used by the form, and to save changes back to the database after it has been edited through the bound controls.

     After doing this simple drag-and-drop operation, the designer writes about 600 lines of code (for you!) to lay out all those controls and hook them up to the data source.

2.   Let’s do one last thing in the designer to make the result a little prettier. Select the PictureBox control that was added for the Photo field, to the right of the Photo: label in the form.

3.   In the Properties window in the bottom right of the Visual Studio IDE, scroll through the list of properties and right-click on SizeMode.

4.   Select Zoom in the drop-down list (see Figure 1.13).

FIGURE 1.13: Setting the SizeMode Property of the PictureBox Control

Setting the SizeMode Property of the PictureBox Control

Running the Application

1.   To run the application, press F5 or select Debug > Start Debugging from the menu.

You should see the application running, as shown in Figure 1.14. Without writing a single line of code by hand, you have a reasonably complex data access form which lets you view a set of records that has data types including text, dates, and images. You can use the navigation controls at the top of the form to page through the records, edit records, create new records, delete records, and save the changes made to records from memory back to the database.

FIGURE 1.14: Running FirstDataApp

Running FirstDataApp

If you aren’t saying “Wow!”, then you are either really hard to impress or you haven’t spent much time trying to write applications like this before using Visual Studio 2005. With past technologies it took writing a lot of code—on par with the thousands of lines of code the designer just wrote for you—to get something like this form hooked up and working correctly. And you had to write that same code over and over for every form like this you needed. It is likely that you made some mistakes along the way and had bugs in your forms that were (hopefully) caught in testing. This probably led to digging around in that code to find the problem and get it working correctly. With the designer writing the code, not only do you get it done in a miniscule fraction of the time, but the code is much more likely to be correct the first time for basic scenarios.

At this point you may be wondering, “If it’s this simple, why do I need this big book to figure out data binding in Windows Forms 2.0?” Well, the real world is never simple. Although the designer simplifies coding common scenarios like the form we just generated, there will always be complex scenarios that your users or your marketing folks will want your application to support and that the designer isn’t capable of coding for you. To address those scenarios, and to better understand all the simpler scenarios where the designer does help you, you need to dig a little deeper and spend a little more time. Also, anytime code is generated for you, it’s risky to proceed with development if you don’t understand the code that was generated. You will have to maintain that code, and you may have to make direct modifications to it or write similar code by hand to support more advanced scenarios. For all these reasons, you need to understand the material covered in the rest of this book.

Data-Binding Landscape

A number of things come into play to make data binding happen. First, you need the data. From the perspective of a presentation layer client application, this comes in the form of in-memory data sources. You need controls or components that are designed to work with that data to automatically present it and push changes back to the data source. This functionality may be encapsulated in the top-level controls that the user sees on the screen, reside in some intermediary component the acts as a middleman between a control type and a data type, or involve a combination of both the control and an intermediary component. If you will have multiple controls on a form that are all bound to the same data source and want those controls to behave as a unit, staying synchronized with changes to the underlying data source, you’re going to need some support from the container of those controls to keep them all in sync. These mechanisms are all present in Windows Forms data binding.

You can use a variety of data sources to accomplish data binding in Windows Forms, such as data sets, custom collections, or individual business objects. You can bind those data sources directly to Windows Forms controls that are part of the .NET Framework, purchase third-party control libraries that support data binding, or write your own data-bound controls. Windows Forms 2.0 introduces a BindingSource component that lets you code complex data-binding scenarios with a lot less—and more maintainable—code. And the Form class itself also has built-in support to manage the synchronization of multiple controls on a form that are all bound to a single data source.

Data Sources

One thing you will need to keep straight as you read this book is the kind of data sources you are working with. You need to deal with several categories of data sources in a data-bound Windows Forms application, such as data sources that exist

•    At the data persistence layer or data tier, including relational databases, XML files, object storage mechanisms, and simple data files of some sort.

•     In the layers in your application, between the data persistence layer (e.g., database) and the data presentation layer (e.g., Windows Forms application), including objects and data structures in the services, and business and data access layers that your Windows Forms application works with. Layered application architecture is discussed later in this chapter and will be mentioned throughout the book; it is an important concept to make a part of your application development strategy.

•    In the Windows Forms application itself. This is the most important kind of data source that we will be focusing on in this book. The application may retrieve those data sources through other layers in your architecture, or it may obtain them directly from the database, through a service, or from files on disk.

Ultimately, data sources in the context of this book are objects in memory within the process of the Windows Forms application. These data sources present data to the user and are the sources users interact with through data-bound controls.

Data Objects and Collections

Data sources in a Windows Forms application are composed of object instances. A data source may be a single instance of a single object, or it may be a collection of object instances, where the collection itself is an instance of a container object. Those instances may be of almost any type, including types in the .NET Framework or types that you create as class or structure definitions. As a result, discussing data binding can get a little confusing, because you have to talk in generalized terms about the things that you are binding to. They may be a DataSet, an ArrayList, a BindingList<Customer>, a Customer, a Foo, or some unknown type that you program against through an interface reference without knowing the actual object type. Additionally, even once you get down to the individual object level, you need to describe the parts of that object that you are using for data binding, and those may be properties, fields, variables, or columns.

Throughout this book, I refer to an object as a data item if it’s contained within some sort of collection that is being used for data binding. That may be an instance of a Customer class within a BindingList<Customer> collection, or it may be a DataRow within a DataTable within a DataSet. I refer to collections of objects as a collection or a list. However, to be used for many data-binding scenarios, a collection has to implement the IList interface to be properly described as a list.

The part of a data item being bound to could be a public property on an object instance, or it could be a column within a data row (also sometimes referred to as a field). For these situations, I use the term property, and if the collection is a data table, you can translate this to mean “the column within the data row that is the current data item.”

You can think of a data member as a relative path to some piece of information within an object that contains data. If the object is a single instance of a data item, then the data member may just be the name of the property on the object that you want to use for data binding. For example, when you set up data binding to a TextBox control (covered in detail in Chapters 3 and 4), you create an instance of the Binding class. The second parameter to the constructor is the data source, and the third parameter is the data member. The following example shows how to pass a reference to an instance of a Customer object as the data source and pass “CompanyName” as the data member:

Customer cust = new Customer();
cust.CompanyName = "Northwind Traders";
Binding bind = new Binding("Text", cust, "CompanyName", true);
m_TextBox.DataBindings.Add(bind);


If the object itself is a container of multiple collections of objects, such as a DataSet that contains more than one DataTable, or is a custom object that has a property that exposes a child collection of objects, then the data member is the name of the property exposed from that container object. For example, when you set up data binding for a BindingSource component, (covered in detail in Chapters 3 and 4) to a complex object hierarchy, you can set the DataSource property to the top-level data container object, and use the DataMember property to resolve the part of that container that holds the list of data you are binding to. For example:

public class Order
{

   public int OrderId { ... }
   public DateTime OrderDate { ... }
   public BindingList<OrderDetail> Details { ... }

}

public class Customer
{   

   public BindingList<T> Orders { ... }
}

public class MyForm : Form
{
   private BindingSource m_BindingSource = new BindingSource();
   Customer m_Customer = new Customer();
   private void OnFormLoad(object sender, EventArgs args)
   {

      m_BindingSource.DataSource = m_Customer;
    m_BindingSource.DataMember = "Orders";
     Binding textBoxBinding =
        new Binding("Text",m_BindingSource, "OrderDate",true);

   }

}


In this example, Orders is the relative path within the Customer object to the list that the BindingSource component is bound to. The data source and data member for that binding source represents a list collection itself. That binding source is then used as the data source for a Binding object, specifying the data member as OrderDate—a path within the current item in the data source list.

DataSets or Not, That Is the Question...

I refer to data sets (specifically, typed data set classes) extensively throughout the book. Chapter 2 covers how data sets work in more detail, but I want to briefly touch on them here to give an overview of how they will be used in this book. The use of data sets in Windows Forms applications is a topic that seems to incite heated debates throughout the .NET development community. Some people object to using data sets within the presentation layer because they assert that this couples your presentation tier to the data tier through the schema contained in the data set. They argue that you need to use custom business objects and collections in the presentation layer to make sure those objects are decoupled from the data tier schema. And depending on how you approach the use of data sets, they may be correct. But if you are smart about when, where, and how you use data sets, they can be a big time saver, help your application perform better, and make it easier to maintain.

You can completely decouple the data sets in your presentation layer from the actual schema in your data tier by defining the data sets that sit in between your presentation and data layers in the layers themselves. You can populate those data sets in your business layer or data access layer by iterating over the data retrieved from your data tier. You would have to do almost the same thing to populate a custom business object collection. By using data sets, you get

•    A highly functional container for data that can be strongly typed

•    Automatic change tracking for contained data

•    Seamless data-binding support

This doesn’t mean that all of the examples in this book use data sets; numerous examples use custom business objects and collections for data binding as well. The mechanisms of Windows Forms support data sets and other kinds of objects equally. If you choose to use custom objects, you will be responsible for writing all of the code yourself to create those objects with the proper patterns and interface implementations to make them work correctly in data-binding scenarios. You will see in Chapter 9 that creating a rich container class for data items that approaches the functionality provided by data sets involves a great deal of work.

If you have a bias against data sets, you should take a look at .NET 2.0. A lot of the shortcomings of data sets in .NET 1.1, particularly with typed data sets, have been overcome in .NET 2.0. As demonstrated in the walkthrough earlier in this chapter, typed data sets give you a lot of power and let Visual Studio write thousands of lines of highly functional data access code for you with just a few simple drag-and-drop operations in the designer. With .NET 2.0, you can also work with data tables on their own without needing to create a data set to contain them.

If you aren’t working with data sets, then the collections you work with will be instances of other types. You can and will most often use one of the rich container classes that are included in the .NET Framework. These include the types defined in the System.Collections namespace, which let you store any kind of object in a type-unsafe way and, even better, the generic collections defined in the System.Collections.Generic and System.ComponentModel namespaces, which allow you to define type-safe collections. In almost all cases in .NET 2.0, you should favor the generic collections over the type-unsafe versions in the System.Collections namespace. Chapter 9 goes into more detail about this, including a discussion about working with custom business objects and collections, but you will see many simple examples before then that use the BindingList<T> generic collection class. You can also use the List<T> class for many data-binding scenarios, but BindingList<T> is a better choice in most cases for Windows Forms data-binding usage. As described in Chapter 9, if you need to, you can define your own collection classes and use them in data-binding scenarios. The interfaces you need to implement for that collection class are described in Chapters 7 and 9.

Data-Bound Controls

Most of the controls that ship with.NET Framework support data binding to some degree, because they all inherit from the Control base class, which implements the IBindableComponent interface. That interface defines the contract for supporting a collection of simple binding objects (instances of the Binding class) through a DataBindings collection on the component that implements the interface. The interface also allows the implementing component to be associated with a BindingContext, which helps keep components that are bound to the same data source synchronized with changes in that data source. More complex controls can also add their own support for more advanced forms of data binding by exposing additional data-binding properties at the control level, such as a DataSource, DataMember, DisplayMember, or ValueMember property.

If the controls that ship with.NET Framework don’t meet your needs, you have a number of options that let you still take advantage of data binding. You could

•    Design your own controls, derived from the Control base class directly or indirectly. At a minimum, your control will inherit these simple data-binding capabilities because it will inherit the implementation of IBindableComponent.

•    Add your own complex data-binding properties to support whatever additional forms of data binding you want.

•    Derive a control from the built-in controls, such as a DataGridView, and inherit all the rich data-binding features already present in that control, while specializing or modifying its behavior to your needs.

•    Get more low level and implement IBindableComponent yourself on any component on which you want to be able to data bind the properties.

•    Turn to the rich market of third-party components available for .NET. These provide specialized behaviors that are intended to save you significant development time for more advanced, but common, data-binding and presentation scenarios.

Chapters 36 cover DataGridView and other data-bound controls, and Chapter 8 discusses how to implement your own data-bound controls.

Layered Application Architecture

I have already mentioned layers in your application several times in this chapter, and I will continue to do so throughout the book. Layered application architecture is a very important concept and something you should consider adopting in any nontrivial application. In layered application architecture, you divide the functions of your application into separate layers. The number of layers you choose is up to you, but the most common approach is to separate your application into presentation, business logic, and data access layers (see Figure 1.15). These represent a stack of layers with the presentation at the top, business logic in the middle, and data access at the bottom. The classes created within each of those layers should be focused on the purpose of that layer, and you should try to keep the concerns of one layer from leaking into the other, especially details from higher layers leaking into lower layers. Because lower layers are also intended to provide isolation, or decoupling, from the details that lie below them, you should also try to avoid leaking too many details up through a layer as well.

FIGURE 1.15: Application Layers

Application Layers

For example, things like controls and drawing are the concerns of the presentation layer, so classes defined in your business logic layer shouldn’t contain direct references to controls if at all possible. If there is complex logic associated with the presentation of controls, you may want to break out a separate presentation logic layer, especially if you are developing a framework for presentation that will be reused across many forms or across multiple applications. The data access layer is intended to hide the intricate details of the data storage tier from the rest of the application. You want to be able to make minor redesign decisions at the data storage tier without having to change details throughout the rest of your application; the extent to which this is possible depends on what you do with the data in your application, as well as the scope of what is changed.

“What is the point?” you might ask. It sounds like a lot of extra complexity. If all your application does is retrieve data from a database, present it on the screen, allow the user to interact with the data, and then store the results back on the database, why can’t you just embed all that data access logic right in the Windows Forms classes that use the data? The answer is that you can, but if you have ever built large complex applications that do those things, you will know that embedding the data access code into the forms themselves leads to maintainability nightmares.

For example, if a query accesses the Customers table in 20 different forms, and then you change the schema of the Customers table, possibly removing or renaming a column, you would now have to track down everywhere in your forms that you were directly accessing the database to get Customer data and fix the queries. If instead you had centralized all the data access against the database into a data access layer, and there is only one class that ever touches the Customers table directly, then you only have to modify one class for the query.

This doesn’t mean that the effects of that change can’t be felt downstream in multiple forms, but it does mean that the frontline damage of a schema change is confined to the data access layer class that touches the table. You will have to analyze how the resulting data is being used to see if you will need to modify the classes that use that data access class.

This also lets you reuse that data access class in multiple places in your application without having to rewrite the query code over and over again, which can be a big time savings. Finally, there is a benefit from the perspective of understanding and maintaining the application. In a large application, it is not uncommon to have different developers who focus on presentation, business logic, and data access. By having all of the data access code separated from the Windows Forms application code, the people coding the Windows Forms stuff don’t have to know a thing about SQL if they don’t want to.

You may also wonder why you should bother with a business layer if you don’t have any complicated business logic in your application that needs to be separated into its own layer. Won’t you end up creating a whole layer with a bunch of classes that do nothing except pass data through from the data access layer to the presentation layer and vice versa? That is a lot of work and code to maintain if it’s not doing any real processing currently.

If you can guarantee that your application will never grow beyond its current complexity, maybe you don’t need to bother with a business layer. However, most applications grow in complexity beyond what they were originally envisioned to do, and they usually involve things like data validation logic, workflow, and processing rules. All these things logically belong in the business layer, and if you didn’t include one in your original architecture, you would need to choose between embedding that code in the presentation layer or data access layer, with all the maintainability downsides described earlier for embedding data access code, or you would need to modify your application architecture to add the code where it belongs. While it is usually perfectly acceptable to add components and code to existing parts of your application architecture as your application evolves, it isn’t usually a good idea to be modifying your application architecture midstream. You will usually end up with an inconsistent mess that may have unexpected side effects, and it will certainly be more difficult to maintain.

A typical configuration for a three-tier smart client application is shown in Figure 1.16. The presentation tier runs the presentation layer code and, possibly, any number of support libraries that could be considered separate layers within the presentation tier as well. Smart client applications will also often have their own local data cache to support offline operations. The business logic and data access layers typically run on a middle-tier application server, and the data storage is done on a separate back-end server as the data tier. For smaller-scale smart client applications that use Web services for communications between the client (presentation tier) and the middle tier, the middle-tier server may also host the Web service that provides the façade into the middle tier that the client communicates through. In larger-scale applications, things may be separated into more tiers, with a presentation (client) tier, Web server tier, business logic and data access middle tier, and a data tier. With the advent of automatic deployment and update mechanisms like ClickOnce, you can also choose to deploy business logic and data access layers to the client machine to harness its processing power, eliminating the need for a middle-tier server, or at least reducing the processing load on it.

FIGURE 1.16: Typical Smart Client Application Architecture

Typical Smart Client Application Architecture

The primary advantage of dividing applications into separate tiers is scalability—being able to leverage the processing power of multiple machines to handle a single application operation. Other benefits include security and fault tolerance. The trade-off is usually performance (any time you cross a process boundary, there is usually a fairly large performance penalty for doing so) and complexity. These are all things that a good architect takes into consideration when deciding how to factor application functionality into layers, processes, and tiers. However, a prerequisite for separating an application into multiple tiers is to first break it up into multiple layers. Each layer provides a decoupling point where you can break the application into multiple tiers if it makes sense to do so.

So, remember that layers represent a logical separation of different portions of the code that implement different portions of the application’s functionality, and the tiers are the physical layers at a machine level that the application is broken up into. You should always strive to divide your application into layers to achieve better decoupling and maintainability, more opportunities for reuse, and more flexibility in determining the application architecture.

In terms of building Windows Forms data applications with .NET, this means that for any serious application, you will always have multiple Visual Studio projects that contain the application code. You will have the Windows Forms project that contains your forms and the event handling logic that sits behind them. You may have some additional class library projects that contain custom controls that are used in the Windows Forms—so those controls can be used across multiple projects—but those controls would still be considered part of the presentation layer. You will then have at least one other class library project that contains the data access layer classes; these get the data from the data tier into your application and pass modified data from your Windows Forms application back to the data tier for storage. If the data layer itself is fairly complex, you may want to divide the data layer into multiple Visual Studio class library projects, one for each category of data that the application works with. For example, the CustomersDataAccess class library could contain all the data access code for customers, orders, and order details, and the SupplyDataAccess class library could contain all the code for the products, suppliers, and shippers.

“What,” you may be asking yourself, “does all this have to do with data binding?” The thing you need to realize is that Visual Studio capabilities have the potential to encourage you to employ bad design practices. As you saw in the walkthrough example earlier in this chapter, there is a rich data-binding experience in Visual Studio within a Windows Forms application if you pull the database information directly into your Windows Forms project, create a typed data set and its associated data adapters in the project, and then set up the data binding based on the data sources that result. However, if you follow that pattern, you are putting data access code directly in your Windows Forms project, which is exactly what you shouldn’t do for the reasons just discussed. So even though you will see a lot of demos that do this—and I even do it in some places in the book to simplify the samples and keep them focused on data binding and not the overall application architecture—you shouldn’t plan on doing this in production applications.

What Is a Smart Client?

The subtitle of this book includes the term smart client, and it’s that kind of application that I had in mind for most of the scenarios used in the examples throughout the book. As such, I think it is worthwhile to quickly define what constitutes a smart client application.

A smart client application is first and foremost a rich client application, or fat client, that runs on the user’s desktop. This most often means a Windows Forms application in a .NET world, but it could also be a Visual Studio Tools for Office application, or it could be a smart device user interface. Smart client applications typically aren’t standalone applications that run exclusively on the user’s desktop; they are most often distributed applications, and the Windows Forms application is just the presentation tier portion of the application that communicates over the network to middle-tier application servers, Web services, or back-end databases.

Smart client applications often support offline use, allowing the application to still be useful when not connected to the network, or when the back-end servers of the application are unreachable, such as when using a laptop computer on an airline or in a customer’s offsite location. Smart client applications can be most effectively operated if they support automatic deployment and update over the network, such as using the ClickOnce technology that is part of .NET 2.0 (and which is the topic of my forthcoming book in this series, written with Duncan Mackenzie). Finally, a smart client ideally runs under a constrained security context on the user’s machine, and it prevents the smart client application from doing anything it wasn’t designed to do, or anything that the user isn’t willing to let it do based on who created the application or where it came from.

This book focuses on presenting data in a Windows Forms application and lets you interact with that data in a rich way. This is only a small slice of the architectural and technological considerations you need to master in order to develop a large-scale smart client application. To design and develop smart client applications, you will also need to become acquainted with distributed communications, data caching and synchronization, automatic deployment and update, and code access security. However, having a rich user interface is one of the most critical factors for moving to a smart client architecture successfully instead of just building Web applications. Learning how to build good data-bound interfaces will help you along the path to being able to build successful smart client applications.

Where Are We?

Well, you are at the beginning, really. This chapter was just intended to get the ball rolling, both to give you a quick sense of what data binding in Windows Forms is all about and what its capabilities are, and more importantly to help you understand where data binding fits into the bigger picture of building real-world, enterprise-scale, smart client data-driven applications in .NET.

Some key takeaways from this chapter are

•    In the context of this book, a data source is a collection of objects or an individual object in memory in the client application that will be used for data binding.

•    You can use data sets or custom collections with equal ease for data binding in Windows Forms 2.0.

•    The terms data sources, data items, properties, and data members should be understood, because the rest of this book assumes that you do.

•    Smart client applications should be designed with separate layers for business logic and data access, and those layers will often be deployed to a separate middle-tier server for large-scale applications.

The next chapter dives into using the new typed data set and table adapter features in .NET 2.0 to get data into your Windows Forms applications to be used as the data source for data-binding scenarios.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.219.33