You use VS05's Data Sources window to identify and create data sources for a project. You open the Data Sources window, shown in Figure 16.15, by choosing Data | Show Data Sources from the VS05 main menu. Figure 16.15. Data Sources Window in VS05
When a project has no data sources, the Data Sources window displays a comment to make sure you know about it, and it gives you two mechanisms for adding a new one: the Add New Data Source link label or its tool strip button counterpart.[8] Either way opens the Data Source Configuration Wizard, shown in Figure 16.16.
Figure 16.16. Data Source Configuration Wizard
Here, you create a data source to encapsulate data stored in a database, a web service, or a .NET type. DatabasesArguably the most common location of data is within a database and, therefore, is the most common data to expose as a data source for data binding. Visual Studio has always provided the means to encapsulate data located in databases using typed data sets. A typed data set is a class that contains one or more database tables, views, stored procedures, and functions, each of which is exposed as a strongly typed .NET class. Each of these needs to be loaded with data from the database and, in some cases, needs to update the database with any changes. This work is performed by a typed table adapter. VS05 automatically creates one for each database object exposed from a typed data set. To use the Data Source Configuration Wizard to facilitate the creation of typed data sets and table adapters, you choose the Database option, as shown in Figure 16.16. This process revolves around selecting one or more tables, stored procedures, or views that will supply the data you require. The next step is to identify the desired database by choosing a database connection, shown in Figure 16.17. Figure 16.17. Choosing a Data Connection
Although supplying a connection string at design time helps our data binding configuration, we'll need the same connection string at run time. Consequently, the Data Source Configuration Wizard next asks you whether you want the database connection to be stored as an application setting, as shown in Figure 16.18.[9]
Figure 16.18. Persisting a Data Connection as an Application Setting
If you choose yes, the setting shown in Figure 16.19 is added to your application-wide settings. Figure 16.19. Storing the Database Connection String as an Application SettingWith your database connection string in hand, the Data Source Configuration Wizard can interrogate the desired database for all database objects that expose data. If the database is SQL Server, this includes tables, views, stored procedures, and functions, as shown in Figure 16.20. Figure 16.20. Choosing Database Objects
After you choose the desired database objects and specify the name of the generated typed data set, you click the Finish button to complete the process. This creates the typed data set with the name you specified as an .xsd file added to your VS05 project root, as shown in Figure 16.21.[10]
Figure 16.21. A Generated Typed Data Set with a Single Table and Corresponding Typed Table Adapter
Any typed data set (.xsd) is automatically detected by VS05whether it was produced via the Data Source Configuration Wizard or added manuallyand is listed in the Data Sources window, as shown in Figure 16.22. Figure 16.22. The Generated Typed Data Set as a Data Source
In Figure 16.22, you can see the new Northwind typed data set, which includes the Employees table. Each field in the table is displayed with an icon that hints at the type of data it represents. Additionally, the middle two tool strip buttons are enabled (they weren't in Figure 16.15). With these two new buttons, the Data Sources window tool strip allows you to edit and reconfigure the typed data set.[11]
Web ServicesAs you know, data sources are simply instances of item or list types. In the case of a database, each table is a list data source. On the other hand, to bind to data exposed via a web service means binding to a type exposed by that service.[12] The purpose of the Data Source Configuration Wizard, with respect to web services, is to turn types exposed from a web service into .NET-specific data sources against which you can bind.
To create a data source for a web service-exposed type, you begin by selecting the Web Service option when you open the Data Source Configuration Wizard, which then opens the Add Web Reference dialog to allow you to locate the desired web service, as shown in Figure 16.23. [13]
Figure 16.23. Choosing a Web Service That Exposes the Type You Want to Turn into a Data SourceYou need to choose a web service that implements web methods that return item or list data source objects. To complete the process, you select the web service's service description, shown in Figure 16.24. This indicates the Web Services Description Language (WSDL) document that enables VS05 to generate a .NET class that maps to the web service.[14]
Figure 16.24. Selecting the WSDL Web Service DescriptionClicking the Add Reference button finalizes your choice. The wizard navigates to the final summary page, which lets you know what you've gotten yourself into, as shown in Figure 16.25. Figure 16.25. Confirming the Addition of the Specified Web Service to Your ProjectWhen you click Finish, the web reference is added to your project, and all types from the web service that expose public properties are automatically listed in the Data Sources window, as shown in Figure 16.26.[15]
Figure 16.26. Web Service Data Sources Available from the Data Sources Window
As with typed data sets, web references added using either the Data Source Configuration Wizard or manually are listed automatically in the Data Sources window. The example in Figure 16.26 shows that the Employees web service we referenced operates over a typed data set for the Northwind database and, consequently, has re-created a familiar-looking data source. However, you can import any type exposed from any web service described with WSDL anywhere in the world. ObjectsAny typed data sets and public types exposed from referenced web services are automatically turned into data sources, but not all other types visible to your project are. The reason is that any object with public properties can conceivably become a data source, so automatically turning them into data sources would become quite unwieldy. To avoid this problem, VS05 supports a model that requires you to opt-in local and referenced .NET types as data sources.[16]
To turn one of these types into a data source, choose Object when you open the Data Source Configuration Wizard. The wizard navigates to a page from which you can choose the desired type, as shown in Figure 16.27. Figure 16.27. Object Data Sources Available from the Current Project
The Data Source Configuration Wizard scans the entire project for possible types, including forms, typed data sets, and web services, all grouped by namespace. With a click of the check box, you can show or hide any types in referenced assemblies that begin with "Microsoft" or "System." Notice in Figure 16.27 that the text box beneath the object list displays a description of the selected object. This description is derived from the XML summary comment at the top of the class: /// <summary> /// RaceCarDriver stores information about a Formula 1 race car driver. /// </summary> class RaceCarDriver : INotifyPropertyChanged {...} When you've picked the desired type, click Finish to turn it into a data source. As with data sources for databases and web services, an object data source appears in the Data Sources window, as shown in Figure 16.28. Figure 16.28. Object Data Source Added to the Data Sources Window
If the desired type is not located in your project, you reference it by clicking the Add Reference button in the Data Source Configuration Wizard (Figure 16.27). This opens VS05's standard Add Reference dialog, shown in Figure 16.29. Figure 16.29. Referencing a .NET Assembly
Here, you can reference .NET assemblies located in the assembly cache, a project, the file system, or the list of most recently referenced assemblies. When you make your choice and click OK, the Data Source Configuration Wizard assembly list is updated with your selection, allowing you to then find the type from which you want a data source to be composed. An example is the Employee type, located in the EmployeesAssembly, as shown in Figure 16.30. Figure 16.30. Selecting the Employee .NET Type to Be Turned into a Data SourceWhen you select your type and click Finish, the new data source is available in the Data Sources window, as shown in Figure 16.31. Figure 16.31. Data Source Based on a .NET Type Located in a Different Assembly
Notice that data sources based on types located in referenced .NET assemblies are categorized by namespace. Configuring the BindingSourceAfter you've designated a type as a data source and you've dropped a BindingSource component onto your form, you reference the former from the latter to enable data binding against the BindingSource. This involves setting the BindingSource component's DataSource property with the desired data source, as shown in Figure 16.32. Figure 16.32. Configuring the BindingSource with a Data Source
All currently identified data sources are listed in the DataSource property's drop-down, under Other Data Sources | Project Data Sources. Note that you also have the option to add a new data source to your project, if you haven't already, using the Data Source Configuration Wizard. In this example, the selected data source is represented in the Properties window, as shown in Figure 16.33. Figure 16.33. BindingSource with a Configured Data Source
The following code is generated by the Windows Forms Designer when a data source is hooked up to a BindingSource from the Properties window (it should seem familiar): // IDEDataBindingForm.Designer.cs partial class IDEDataBindingForm { ... BindingSource bindingSource; ... void InitializeComponent() { ... this.bindingSource = new BindingSource(this.components); ... // bindingSource this.bindingSource.DataSource = typeof(DataBindingFundamentalsSample.RaceCarDriver); ... } } For data sources that aren't containers for other data sources (such as typed data sets), you need only set the DataSource property. However, for those that are containers, you also need to identify the contained data source you'd like to bind to. Contained data sources are known as data members and are referenced from the BindingSource component's aptly named DataMember property. Use the Properties window, as shown in Figure 16.34. Figure 16.34. BindingSource with a Configured Data Source and Data Member
The Properties window is smart enough to inspect the data source for all possible data members and, as you can see in Figure 16.33, list them for your selection. The Windows Forms Designer-generated code to reflect your selection is shown here: // IDEDataBindingForm.Designer.cs partial class IDEDataBindingForm { ... void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.bindingSource = new BindingSource(this.components); this.northwindDataSet = new NorthwindDataSet(); this.employeesTableAdapter = new EmployeesTableAdapter(); ... // bindingSource this.bindingSource.DataMember = "Employees"; this.bindingSource.DataSource = this.northwindDataSet; ... // northwindDataSet this.northwindDataSet.DataSetName = "NorthwindDataSet"; ... // employeesTableAdapter this.employeesTableAdapter.ClearBeforeFill = true; ... } ... IContainer components = null; BindingSource bindingSource; NorthwindDataSet northwindDataSet; EmployeesTableAdapter employeesTableAdapter; } As you can see, the BindingSource component's DataSource and DataMember properties are set as expected. Perhaps unexpectedly, however, the Windows Forms Designer has taken the liberty of adding the NorthwindDataSet component to the form, referencing it directly from the DataSource property and eschewing the special typeof syntax. This special behavior is covered in Chapter 17. An EmployeesTableAdapter component has also been added to the form. When a data member is selected for a data source that's a typed data set, the Windows Forms Designer is smart enough to find a corresponding typed table adapter, if one exists, and drop it onto the form. Typed table adapters are also components, and their primary role is to facilitate data persistence for the database object that's represented by the data member. Data Source Persistence
In most cases, data sources need to be filled, at least initially, with data from a data store. For typed data sets, the role of managing persistence is delegated to typed table adapters, one of which is created for each data member in a typed data set. When you use the Properties window to configure a BindingSource component's DataSource and DataMember properties, the Windows Forms Designer not only adds both typed data sets and typed table adapters to a form, but it also generates the following code to load the typed data set with data from the database: // IDEDataBindingForm.cs partial class IDEDataBindingForm : Form { ... void IDEDataBindingForm_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the // 'northwindDataSet.Employees' table. You can move // or remove it, as needed. this.employeesTableAdapter.Fill(this.northwindDataSet.Employees); } } In this code, the typed table adapter loads data into the Northwind typed data set's Employees table by invoking the former's Fill method. Details of the database connections and commands are handled internally by both the typed data set and the table adapter. In fact, if you saved the database connection string as an application setting, the typed table adapter interrogates the setting directly. Although the code to load a typed data set is generated for you, you're on your own if you need to update the data store with any changes. The typed table adapter exposes the Update method for just this purpose: // IDEDataBindingForm.cs public partial class IDEDataBindingForm : Form { ... void IDEDataBindingForm_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the // 'northwindDataSet.Employees' table. You can move // or remove it, as needed. this.employeesTableAdapter.Fill(this.northwindDataSet.Employees); } void IDEDataBindingForm_FormClosing( object sender, FormClosingEventArgs e) { // Save updates back to the Northwind database's Employees table this.employeesTableAdapter.Update(this.northwindDataSet.Employees); } } It's easy for the Windows Forms Designer, typed data sets, and table adapters to provide a persistence framework because they all leverage ADO.NET, which provides a consistent, reliable model for doing so. Unfortunately, the same is not true for data sources created from types located in web services or assemblies. In these situations, you need to manually write the code to load and save data. Whether you can load data into or save data from a data source, however, the simple act of specifying a BindingSource component's DataSource (and, if required, DataMember) properties does allow you to declaratively bind your UI. |