356 Microsoft ADO.NET 4 Step by Step 5. Run the program. When the form appears, it displays the first record from the CourseCatalog table. Chapter 21 Binding Data with ADO.NET 357 Building the WPF project is simple using drag-and-drop techniques, but as the example proj- ect demonstrates, it’s possible to view only the initial record in the incoming table. The fol- lowing language-specific projects add navigation features. Adding Navigation to a Data-Bound WPF Window: C# Note This exercise continues the initial WPF exercise in this section. 1. Add four B utton controls from the Toolbox panel to the WPF window surface. Name the buttons ActFirst, ActPrevious, ActNext, and ActLast; set their Content property val- ues to First, Previous, Next, and Last, respectively. 2. Double-click the ActFirst button control. When the event handler appears, add the fol- lowing code: // Move to the first record in the table. System.Windows.Data.CollectionViewSource catalogSource = (System.Windows.Data.CollectionViewSource) this.FindResource("courseCatalogViewSource"); catalogSource.View.MoveCurrentToFirst(); 3. Back on the window design surface, double-click the ActPrevious button control. When the event handler appears, add the following code: // Move to the previous record in the table. System.Windows.Data.CollectionViewSource catalogSource = (System.Windows.Data.CollectionViewSource) this.FindResource("courseCatalogViewSource"); if (catalogSource.View.CurrentPosition > 0) catalogSource.View.MoveCurrentToPrevious(); 358 Microsoft ADO.NET 4 Step by Step 4. Back on the window design surface, double-click the ActNext button control. When the event handler appears, add the following code: // Move to the next record in the table. System.Windows.Data.CollectionViewSource catalogSource = (System.Windows.Data.CollectionViewSource) this.FindResource("courseCatalogViewSource"); catalogSource.View.MoveCurrentToNext(); if (catalogSource.View.IsCurrentAfterLast) catalogSource.View.MoveCurrentToPrevious(); 5. Back on the window design surface, double-click the ActLast button control. When the event handler appears, add the following code: // Move to the last record in the table. System.Windows.Data.CollectionViewSource catalogSource = (System.Windows.Data.CollectionViewSource) this.FindResource("courseCatalogViewSource"); catalogSource.View.MoveCurrentToLast(); 6. Run the program. When the form appears, it displays the first record from the CourseCatalog table. Use the new navigation buttons to move through the records in the bound table. Adding Navigation to a Data-Bound WPF Window: Visual Basic Note This exercise continues the initial WPF exercise in this section. 1. Add four B utton controls from the Toolbox panel to the WPF window surface. Name the buttons ActFirst, ActPrevious, ActNext, and ActLast; set their Content property val- ues to First, Previous, Next, and Last, respectively. Chapter 21 Binding Data with ADO.NET 359 2. Double-click the ActFirst button control. When the event handler appears, add the fol- lowing code: ' Move to the first record in the table. Dim catalogSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CourseCatalogViewSource"), System.Windows.Data.CollectionViewSource) catalogSource.View.MoveCurrentToFirst() 3. Back on the window design surface, double-click the ActPrevious button control. When the event handler appears, add the following code: ' Move to the previous record in the table. Dim catalogSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CourseCatalogViewSource"), System.Windows.Data.CollectionViewSource) If (catalogSource.View.CurrentPosition > 0) Then _ catalogSource.View.MoveCurrentToPrevious() 4. Back on the window design surface, double-click the ActNext button control. When the event handler appears, add the following code: ' Move to the next record in the table. Dim catalogSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CourseCatalogViewSource"), System.Windows.Data.CollectionViewSource) Dim totalItems = Aggregate vw In catalogSource.View Into Count(True) If (catalogSource.View.CurrentPosition < (totalItems - 1)) Then _ catalogSource.View.MoveCurrentToNext() 360 Microsoft ADO.NET 4 Step by Step 5. Back on the window design surface, double-click the ActLast button control. When the event handler appears, add the following code: ' Move to the last record in the table. Dim catalogSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CourseCatalogViewSource"), System.Windows.Data.CollectionViewSource) catalogSource.View.MoveCurrentToLast() 6. Run the program. When the form appears, it displays the first record from the CourseCatalog table. Use the new navigation buttons to move through the records in the bound table. Understanding WPF Data Binding The DataSet, TableAdapter, and TableAdapterManager instances used in the Windows Forms bound data example earlier in this chapter also appear in the WPF example. That’s because those portions are generated by the Data Source Configuration Wizard; they are not depen- dent on the type of project in which they appear. In WPF, as in Windows Forms, they manage retrieving the data from the external data source and propagating any changes from the ap- plication back to the data source. The binding elements that connect the DataSet content to the on-window fields vary sig- nificantly between WPF and Windows Forms. Much of a WPF application is declared using XAML, and data bindings are no different. To enable data binding, Visual Studio adds infor- mation on the data source to the Grid control that hosts the individual data controls. <! Attributes not relevant to the discussion have been removed. > <Grid DataContext="{StaticResource CourseCatalogViewSource}" Name="Grid1" > Chapter 21 Binding Data with ADO.NET 361 The D ataContext attribute defines the data source for all subordinate elements, which in this case will be the individual data-bound controls found inside of the Grid1 grid. CourseCatalogViewSource is defined a little earlier in the XAML. <Window.Resources> <my:CourseDataSet x:Key="CourseDataSet" /> <CollectionViewSource x:Key="CourseCatalogViewSource" Source="{Binding Path=CourseCatalog, Source={StaticResource CourseDataSet}}" /> </Window.Resources> CourseCatalogViewSource is an instance of CollectionViewSource (actually, it’s known as the CollectionView class by the time the XAML bubbles up into actual code), which is a wrapper around data sources that makes navigation of those sources convenient for WPF applications. In this case, that data source is the CourseDataSet data set, as identified in this same XML block. The important part of the CourseCatalogViewSource definition is the Binding component. {Binding Path=CourseCatalog, Source={StaticResource CourseDataSet}} This content identifies the source of the data that will bind to the controls. As with the form- hosted BindingContext in Windows Forms applications, the Binding entry defines both a source (the DataSet instance) and a path within the source (the DataTable name). Within the XAML definitions for an individual data-bound control, the Binding entry appears again to identify the path to the individual column hosted by that control. This code block defines the TextBox control that hosts the CourseCatalog.CourseName field. <! Attributes not relevant to the discussion have been removed. > <TextBox Name="CourseNameTextBox" Text="{Binding Path=CourseName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" /> This entry specifies the path (the CourseName column) relative to the DataContext estab- lished by the enclosing Grid control (Grid1). The binding ties to the Text attribute, which will display the bound content in the editable portion of the control. Part of XAML’s power is that bound data can flow into almost any attribute exposed by a control. In fact, the entire XAML binding system extends to non-controls as well, allowing nearly any aspect of a WPF applica- tion definition to be configured by bound data from a variety of sources, both internal and external to the application. 362 Microsoft ADO.NET 4 Step by Step Although the drag-and-drop operation that built the WPF window included enabled text boxes and clickable CheckBox controls, the application will not return any data changes to the database. Also, you cannot add or delete records through the default bound application. To enable these features, you must update the bound DataSet directly, adjusting the con- tent exposed through each DataTable instance’s Rows collection as needed. Calls to DataSet. AcceptChanges and the table adapter’s Update method will send any changes back to the source and trigger a refresh of the displayed results. Binding Data in ASP.NET ASP.NET is Visual Studio’s standard web application development solution. Although the development experience is similar to that of Windows Forms and other Visual Studio project types, running ASP.NET applications exist to generate valid HTML and related Web-centric scripting content for consumption by a web browser. All application components, including any data-bound controls, flow to the user’s screen as ordinary web content. Note ASP.NET is not included in either the C# or the Visual Basic flavors of the Visual Studio 2010 Express Edition product. Express Edition users must instead obtain Visual Web Developer 2010 from Microsoft’s Visual Studio Express web site http://www.microsoft.com/express/Web/. Creating Data-Bound ASP.NET Applications ASP.NET applications in Visual Studio support some drag-and-drop data-bound functional- ity, although the default data presentation options are not as varied as those found in either Windows Forms or WPF projects. The following projects guide you through the process of adding a read-only data-bound grid to a new ASP.NET project. Creating a Data-Bound ASP.NET Page 1. Create a new ASP.NET web application project using either Visual Basic or C#. The new project displays an ASP.NET page in source view. Click the Design display mode button along the bottom of the Default.aspx page panel. Chapter 21 Binding Data with ADO.NET 363 2. Clear out some of the default content to make room for the bound data content. Just above the “Welcome to ASP.NET” message in the page, click the MainContent (Custom) tab. This selects the content within the tab’s panel. Press Delete to remove the content. 3. Access the Server Explorer panel (or the Database Explorer panel depending on your edition of Visual Studio). Expand the branch for the book’s sample database. (You might need to add it as a new connection if it does not appear in the panel.) Within that branch, expand the Tables item. The CourseCatalog table should appear in the panel. 364 Microsoft ADO.NET 4 Step by Step 4. Drag CourseCatalog from the Server Explorer panel (or the Database Explorer panel) to the blank area within the MainContent (Custom) tab in the web page. This action adds an ASP.NET GridView control to the page, already configured with the table’s columns. It also adds a SqlDataSource control just below the grid. 5. Run the application. Visual Studio starts up a web browser session and displays the data-bound grid in the web page that appears in the browser. Understanding ASP.NET Data Binding As with Windows Forms, a data-bound ASP.NET application uses controls that encapsulate database access and data-binding behaviors. But whereas the Windows Forms example ear- lier in this chapter added nearly a half-dozen data-enabled intermediate controls to work its binding magic, not to mention the final display controls, the ASP.NET sample gets by with only two controls: the data source and the grid control. Chapter 21 Binding Data with ADO.NET 365 Within the markup for an ASP.NET application, controls appear as special HTML tags prefixed with “asp.” Behind the scenes, the implementation for these special tags is a standard .NET class, a system that has a closer relationship with a WPF user interface than to a Windows Forms UI. The following code defines the data source that Visual Studio created when you dragged the CourseCatalog table to the page surface: <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:StepSampleConnectionString1 %>" DeleteCommand="DELETE FROM [CourseCatalog] WHERE [CourseID] = @CourseID" InsertCommand="INSERT INTO [CourseCatalog] ([CourseID], [CourseName], [OfferedFall], [OfferedSpring], [CreditHours], [Prerequisite]) VALUES (@CourseID, @CourseName, @OfferedFall, @OfferedSpring, @CreditHours, @Prerequisite)" ProviderName="<%$ ConnectionStrings: StepSampleConnectionString1.ProviderName %>" SelectCommand="SELECT [CourseID], [CourseName], [OfferedFall], [OfferedSpring], [CreditHours], [Prerequisite] FROM [CourseCatalog]" UpdateCommand="UPDATE [CourseCatalog] SET [CourseName] = @CourseName, [OfferedFall] = @OfferedFall, [OfferedSpring] = @OfferedSpring, [CreditHours] = @CreditHours, [Prerequisite] = @Prerequisite WHERE [CourseID] = @CourseID"> <DeleteParameters> <asp:Parameter Name="CourseID" Type="String" /> </DeleteParameters> <InsertParameters> <asp:Parameter Name="CourseID" Type="String" /> <asp:Parameter Name="CourseName" Type="String" /> <asp:Parameter Name="OfferedFall" Type="Boolean" /> <asp:Parameter Name="OfferedSpring" Type="Boolean" /> <asp:Parameter Name="CreditHours" Type="Int16" /> <asp:Parameter Name="Prerequisite" Type="String" /> </InsertParameters> <UpdateParameters> <asp:Parameter Name="CourseName" Type="String" /> <asp:Parameter Name="OfferedFall" Type="Boolean" /> <asp:Parameter Name="OfferedSpring" Type="Boolean" /> <asp:Parameter Name="CreditHours" Type="Int16" /> <asp:Parameter Name="Prerequisite" Type="String" /> <asp:Parameter Name="CourseID" Type="String" /> </UpdateParameters> </asp:SqlDataSource> This definition includes sufficient content to define both the DataSet instance and the DataAdapter that loads data into it. The asp:SqlDataSource control (as implemented through the System.Web.UI.WebControls.SqlDataSource class) includes the logic needed to create a DataSet instance and fill it with incoming data from a DataAdapter. The connection string, referenced in the control’s ConnectionString attribute, appears in the project’s Web.config XML file. . the application. 362 Microsoft ADO. NET 4 Step by Step Although the drag-and-drop operation that built the WPF window included enabled text boxes and clickable CheckBox controls, the application. http://www .microsoft. com/express/Web/. Creating Data-Bound ASP .NET Applications ASP .NET applications in Visual Studio support some drag-and-drop data-bound functional- ity, although the default data presentation options are not. 356 Microsoft ADO. NET 4 Step by Step 5. Run the program. When the form appears, it displays the first record from the CourseCatalog table. Chapter 21 Binding Data with ADO. NET 357 Building