
Beginning Visual C++ 2005 (2006) [eng]-1
.pdf
Accessing Data Sources in a Windows Forms Application
Figure 22-17
You can see that three objects have been added to the project as a result of adding the data source: the NorthWindDataSet object that encapsulates the database, the CustomersTableAdapter object that accesses the data in the Customers table in the database, and the CustomersBindingSource object that manages the communications between the database and the DataGridView control.
The application is now complete, and so far you have not written a single line of code. That’s quite remarkable considering the amount of function you have in the program; however, when I ran the program, the column headers look a little cramped. I prefer the column widths to be set to accommodate the text in the rows, so I couldn’t resist adding the following two lines of code to the Form1 class constructor:
dataGridView->AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode::AllCells;
dataGridView->AutoResizeColumnHeadersHeight();
The application window now looks as shown in Figure 22-18.
1119

Chapter 22
Figure 22-18
You can use the scrollbars to navigate the data and your mouse wheel should scroll the rows. The BindingNavigator control could improve things a bit, so next you’ll see how to use that.
Using the BindingNavigator Control
The BindingNavigator control has been specifically designed to work with a BindingSource component. To use a BindingNavigator control to navigate the data from a data source could not be simpler; you just add the control to the form and set the value of the BindingSource property for the control to the variable encapsulating the BindingSource component. The next Try It Out extends Ex22_03 to do that.
Try It Out |
Using a BindingNavigator Control |
Click the BindingNavigator control in the Toolbox window and then click in the client area of the form to add it to the project. If you open the Properties window for the control, you are able to set the value for the BindingSource property to customersBindingSource, which is the name of the handle to the BindingSource control that encapsulates the Customers table. That’s it; you’re done. If you recompile and rerun the application, you see that the application window now has a toolbar for navigating the data, as shown in Figure 22-19.
You can click the button arrows to progress forwards and backwards through the data records, and there are also buttons to go to the first or last records. If you type a record sequence number in the text box on the toolbar and press Enter, you’ll go directly to that record. The ability to navigate through the records works in whatever sequence they are in. You could sort the records in country order by clicking the header for the Country column to sort the records, and you’ll then be able to navigate through them in that sequence. The BindingNavigator control also provides buttons for adding a new record and deleting a record.
Each of the buttons provided by the BindingNavigator control connects to a member of the BindingSource object being navigated:
1120

Accessing Data Sources in a Windows Forms Application
Figure 22-19 |
|
|
|
Toolbar Control |
Action |
|
|
Move First |
Calls the MoveFirst() function for the BindingSource control |
|
object, which changes the current record for the underlying data |
|
source to be the first record. |
Move Previous |
Calls the MovePrevious() function for the BindingSource con- |
|
trol object, which changes the current record for the underlying |
|
data source to be the previous record if there is one. |
Current Position |
Corresponds to the value of the Current property for the Bind- |
|
ingSource object, which is the current record in the underlying |
|
data source. |
Total Number of Items |
Corresponds to the value of the Count property value for the |
|
BindingSource object, which corresponds to the number of |
|
records in the underlying data source. |
Move Next |
Calls the MoveNext() function for the BindingSource control |
|
object, which changes the current record for the underlying data |
|
source to be the next record if there is one. |
Move Last |
Calls the MoveLast() function for the BindingSource control |
|
object, which changes the current record for the underlying data |
|
source to be the last record. |
Add New |
Calls the AddNew() function for the BindingSource object. This |
|
has the effect of calling EndEdit() to execute any pending edit |
|
operations for the underlying data source and creates a new record |
|
in the list maintained by the BindingSource object. This does not |
|
update the underlying data source. |
Delete |
Calls the RemoveCurrent() function for the BindingSource |
|
object to remove the current record from the list. This does not |
|
modify the underlying data source. |
|
|
1121

Chapter 22
Thus clicking a button on the navigator toolbar initiates an action in the BindingSource object that is managing the data source, but none of the default operations change the database that the BindingSource component is managing. To do that you must write some code.
Try It Out |
Updating a Database |
You are going to have to do something extra when the user clicks a button in the BindingNavigator control to add a new record or to delete a record. The way to do this is to implement a handler function to deal with a Click event for the buttons.
As you already know, you can add a Click event handler for a button by double-clicking the button in the Design tab, so add handler functions for the Add New and Delete buttons on the toolbar. When you click either button at the moment, everything has been put in place in the BindingSource component to allow the database to be updated. All you have to do is call the Update() function for the table adapter object for the table that is to be updated. This function throws an exception if things go wrong, so you must put the call in a try block and catch any exception that may be thrown. Here’s how you can implement the handler function for the Add New button Click event:
System::Void bindingNavigatorAddNewItem_Click(System::Object^ sender, System::EventArgs^ e)
{
try
{
CustomersTableAdapter->Update(Customers->_Customers);
}
catch (Exception^ ex)
{
MessageBox::Show(L”Update Failed!\n”+ex, L”Database Record Update Error”, MessageBoxButtons::OK, MessageBoxIcon::Error);
}
}
The argument to the Update() function must be the name of the data table that contains the values that are to be written to the database, so in this case it’s the _Customers member of the Customers object in the Form1 class. If things don’t go as well as expected, you display a message box explaining the problem. The message box shows the text from the Exception object that was thrown, and this explains the cause of the problem.
The implementation of the Click event handler for the Delete button is almost identical:
private: System::Void bindingNavigatorDeleteItem_Click(System::Object^ sender, System::EventArgs^ e)
{
try
{
CustomersTableAdapter->Update(Customers->_Customers);
}
catch (Exception^ ex)
{
1122

Accessing Data Sources in a Windows Forms Application
MessageBox::Show(L”Delete Failed!\n”+ex, L”Database Record Delete Error”, MessageBoxButtons::OK, MessageBoxIcon::Error);
}
}
The only difference is in the text in the message box. With these two handler functions in place, you should be able to add new customer records and delete existing records.
Binding to Individual Controls
You can also create a Windows Forms application that binds each column on a database table to a separate control; what’s more, you’ll find this easier and quicker than the previous example. Start by creating a new CLR project using the Windows Forms Application template with the name Ex22_04. The next step is to add a data source to the project, and again you will be working with a single table. Press Shift+Alt+D to display the Data Sources window and click Add New Data Source. You can use the Northwind database or a database of your choice, but keep in mind that you have a separate control on the form for each column in the table that you choose. To keep the number of controls manageable, for the Northwind database I suggest you select the Order Details table, as shown in Figure 22-20, because it has only five columns.
Figure 22-20
When you click the Finish button, the Data Sources window shows the Northwind database as the data source with just the Order Details table available. Click the Order Details table name to select it and then click the down arrow to the right to display the menu shown in Figure 22-21.
1123

Chapter 22
Figure 22-21
The top three menu items enable you to choose the controls to be used with the table when you add the data source to the form. If you click the DataGridView item from the menu, you are selecting that control as the one to be for displaying the table, whereas clicking on the Details item indicates you want one control per table column. If you click the [None] item, you are indicating you want no controls to be created when you add the data source to the form. The last menu item opens a dialog box for changing the default control for the table from the current default of DataGridView and for customizing the choice of controls. In this instance, you should just click Details because you want one control for each table column.
You now have to decide which control you want to use for each table column. You can extend the tree that shows the column names in the Order Details table name by clicking the + symbol to the left of the table name. If you then click the first column name to select it, you’ll see that you can display a menu for that, too, by clicking the down arrow. The menu is shown in Figure 22-22.
You can choose any of the controls shown in the menu, but I suggest a TextBox control is most appropriate for the OrderID column. You need to repeat the process for each table column; you can choose a NumericUpDown control for the Quantity column and select a TextBox control for each of the others.
Note that selecting the Customize menu option in the Data Sources pane shown in Figure 22-22 displays the Options dialog box in which you can change the selection of controls available for displaying different types of data. You can also change the control to be selected by default when you drag an item from the Data Sources pane to a form. Figure 22-23 shows the Options dialog box.
1124

Accessing Data Sources in a Windows Forms Application
Figure 22-22
Figure 22-23
Figure 22-23 shows the controls associated with displaying a list, and there is a separate list of associated controls for each of the data types you can select. I have checked the ComboBox and ListBox controls in addition to the DataGridView default, so all three controls are options for displaying a list of data items. You can choose other data types in the drop-down list box at the top of the dialog box for which you want to modify the choice of controls available.
1125

Chapter 22
The final step to create the program is to drag the Order Details table from the Data Sources window to the client area of the form window. The Design tab in the Editor pane will then look similar to that shown in Figure 22-24.
Figure 22-24
I have changed the Text property for the form to make the text in the title bar a little more relevant, and I repositioned the controls slightly so they are better located within the client area. I also rearranged the items in the grey area at the bottom to make them all visible in the Design pane. You can see that five controls corresponding to the five table columns have been added automatically to the form as well as label controls to indicate which is which. There’s a BindingNavigator control at the top of the client area for navigating the table data. Below the form you can see that the application has a BindingSource component that links the database to the controls, and the DataSet and table adapter classes are also identified.
If you press Ctrl+F5 to build and execute the program, you’ll have a complete working program for viewing and editing the Order Details table in the Northwind database. There is a Save button that has been added to the BindingNavigator toolbar that you click to store any changes you make back in the database table. Figure 22-25 shows the application window.
You could create a program that uses the DataGridView control to display a table in essentially the same way. If you want to try it, just create another project and add the data source as in the previous example. If you then immediately drag the table from the Data Sources window to the form, the application is complete. You need only set Text property for the form for the title bar text and set the value of the Dock property for the DataGridView control before compiling and running the program.
1126

Accessing Data Sources in a Windows Forms Application
Figure 22-25
Working with Multiple Tables
Creating an application that works with multiple tables is almost as easy as the previous example. In this example, you’ll use a tab control to allow three different tables in the Northwind to be accessed. Create a new Forms project with the name Ex22_05, and press Shift+Alt+D to open the Data Sources window. Add the Northwind database to the project with the Customers, Products, and Employees tables checked.
Add a TabControl control from the Containers group in the Toolbox window to the form and set the Dock property value for the tab control to Fill. If you click the arrow at the top right of the control, you’ll be able to add a third tab page to the control. You can move between the tabs on the TabControl control using the Tab key, or by clicking the tab page label twice; take care not to double-click the control or you’ll generate handler functions for it. Move to the first tab page and set its Text property value
to Employees. You can then set the Text property value for the other two tabs to Customers and
Products.
You should also add a Panel control to each tab page with its Dock property value set to Fill. This is necessary to locate the BindingNavigator and DataGridView controls properly on the tab page. If you add them directly to the tab, setting the DataGridView Dock property to Fill with the
BindingNavigator control docked to the top of the tab page, the column headers for the DataGridView control are hidden by the BindingNavigator control. This won’t happen Within a Panel container.
You might also want to change the Text property value for the form to something relevant — I made it
“Accessing Multiple Tables.”
You can now drag the Customer table from the Data Sources window to the panel on the tab page labeled Customers. A DataGridView control IS added to the panel, and a BindingNavigator control appears at the top of the form. You’ll want each tab page to have its own BindingNavigator control, so having it placed on the form is not convenient. You’ll need to move it to the panel on the tab page. You can do this by first setting the Dock property value for the BindingNavigator control to None and then dragging the control on to panel on the Customers tab page.
1127

Chapter 22
After you have added the table to the Customers tab page, switch to the next tab before dragging the next table on to its panel from the Data Sources window. When you have added the appropriate table to the panels on the other two tab pages, they each contain a DataGridView control, but no BindingNavigator control — this was not added because you have one already from adding the Customers table. You could add BindingNavigator controls to these tab pages from the Toolbox window, but there’s a shortcut you can use. Click the BindingNavigator control on the Customers tab page and press Ctrl+C to copy it to the Clipboard. Switch to one of the other tab pages, select its panel, and press Ctrl+V to copy the control from the Clipboard to the panel on the tab page. Switch to the third tab page, select its panel, and then press Ctrl+V once more to add a BindingNavigator control to the panel on that tab page. You can then set the Dock property value for each of the three BindingNavigator controls to Top and the Dock property value for each of the DataGridView controls to Fill.
The two BindingNavigator controls that are copies have their BindingSource property values set incorrectly, so select the value field for the property for each of these controls and select the correct BindingSource component from the drop-down list. You should select EmployeesBindingSource for the control on the Employees tab page, and ProductsBindingSource for the control on the Products tab page.
If you press Ctrl+F5 to build and execute the example, you should see the application window shown in Figure 22-26.
Figure 22-26
This all works with no coding at all. I think you’ll agree that this is an amazing capability for generating applications to access data sources.
1128