Lesson 5: Binding, Viewing, and Filtering Data

Lesson 5: Binding, Viewing, and Filtering Data

Viewing data is a vital part of many applications. Data binding allows you to associate records in a data source with controls on a form, allowing them to be browsed and updated. In this lesson, you will learn how to use ADO.NET to bind data to controls in your application and how to manage the currency of records in your application. You also will learn how to use the DataView class to create filterable and sortable views of DataTables and how to manage multiple DataViews with the DataViewManager class.

After this lesson, you will be able to

  • Describe the role of a data provider

  • Describe the role of a data consumer

  • Explain how to bind a property of a data consumer to a data provider

  • Describe how currency is managed in Windows Forms

  • Explain how to filter and sort data with the DataView component

  • Describe the role of a DataViewManager and how to use one

Estimated lesson time: 45 minutes

Data Binding

Data binding refers to a relationship between a data provider and a data consumer. A data provider is a source for data and is linked to a data consumer, which receives data and processes or displays it. A traditional example of data binding is the relationship between a data-bound control, such as a TextBox, and a data source. The control displays the value of the column in the data source to which it is bound at the current row. As the current row changes, the value displayed by the control also changes.

Data Providers

In a data-binding relationship, the data provider is the object that provides data to bound properties and controls.

NOTE
In this context, the term data provider refers to any object that data consumers can be bound to, and does not refer to the data provider suite of components that facilitate disconnected database access.

In the .NET Framework, any object that implements the IList interface can be a data provider. This not only includes ADO.NET objects, such as DataSets, Data Tables, and DataColumns, but also more mundane objects such as arrays or collections. DataViews, which are discussed later in this lesson, are a customizable view of data that can act as a data provider.

Data providers also manage the currency of data. In previous data access technologies, a cursor was used to manage data currency. As the cursor moved, the current record changed and bound controls were updated. Because data access in ADO.NET is fundamentally disconnected, there is no concept of a database cursor. Rather, each data source has an associated CurrencyManager object that keeps track of the current record. CurrencyManager objects are managed through a form s BindingContext object. Data currency is discussed in detail later in this lesson.

Data Consumers

The data consumer represents the control with bound properties. In the .NET Framework, you can bind any property of any control to a data source, provided that the property is accessible at run time. For example, you could bind the Size property of a control to a database record, or the location, or any other run-time accessible property of the control.

Data binding has a wide variety of uses. A typical scenario that involves data binding is a data entry form. Several controls, such as TextBox, CheckBox, ListBox, and so on are bound to relevant columns of a DataSet. New records are entered manually by typing values for each column into the appropriate controls displayed on the form. When a record is complete, it is added to the DataSet, which then can be used to update the database.

There are two types of data binding: simple binding and complex binding. A simple-bound control binds one record at a time to a control. For example, a Label control can be simply bound to a column in a DataTable. In such a case, it would display the member of that column for the current record. Complex binding, on the other hand, allows multiple records to be bound to a single control. Controls such as ListBox or ComboBox can be complex bound to a single column in a DataTable or DataView. At run time, these controls display all members of that column rather than only the current row. Complex-bound controls are usually involved in displaying choices and allowing specific rows of data to be chosen. Controls such as the DataGrid are capable of even more complex binding and can be bound to all columns and rows of a particular DataTable or DataView, or even to a DataSet.

Creating a Simple-Bound Control

You can create a simple-bound control through the DataBindings property. The DataBindings property is an instance of the ControlBindingsCollection class that keeps track of and organizes which controls are bound to what data sources. At design time, the DataBindings property is displayed as a node in the Properties window. This node expands to list the properties that are most commonly data bound, as shown in Figure 6.5.

figure 6-5 commonly data-bound properties.

Figure 6-5. Commonly data-bound properties.

To bind one of these properties to a data source, click the box next to it in the DataBindings node and open the resulting drop-down menu. A list of available data providers is displayed. Available DataSet objects are displayed as expandable nodes that reveal the available DataTable objects. Any DataView objects are also listed. Each of these can be expanded to reveal a list of columns provided by the data source. Browse through the list to the appropriate column and select it. This creates the binding for your control.

You can bind any property of your control to a data source. If you want to bind a property that is not listed beneath the DataBindings node, you can click the (Advanced) box under the DataBindings node and click the ellipses ( ) in the box to view the Advanced Data Binding dialog box, as shown in Figure 6.6.

figure 6-6 the advanced data binding dialog box.

Figure 6-6. The Advanced Data Binding dialog box.

The Advanced Data Binding dialog box lists all of the run-time available properties of the control and allows you to choose the column to bind to the property.

To bind a property to a data source at design time

  1. In the Properties window, expand the DataBindings node.

  2. If the property you want to bind to a data source is listed beneath the node, choose the appropriate column of data from the drop-down menu.

    If the property you want to bind is not listed, click the ellipses ( ) next to the (Advanced) box to open the Advanced Data Binding dialog box. Choose the property you want to bind, and in the adjacent box, choose the column of data to bind to it.

Data Binding at Run Time

At run time, you might want to change the data source a control is bound to. Or, at design time, you might not know what data source a particular control might be bound to. In a third scenario, you might want to bind your control to an array or collection that is not instantiated until run time, in which case you must set the binding in code. Data binding for a control is managed through the control s Data Bindings property, which is an instance of a ControlBindingsCollection object. At run time, you can add, remove, or clear data binding information by setting the appropriate member of the DataBindings collection.

You can bind a property to a data source by using the DataBindings.Add method. This creates a new binding association and adds it to the DataBindings collection. The Add method takes three parameters: the property name you want to bind, as a string; the data source you want to bind to, as an object; and the data member of the data source to which you want to bind the property. The following code example demonstrates how to bind the Text property of a TextBox control to the CustomerID column of a table named Customers in a DataSet named DataSet1:

Visual Basic .NET

TextBox1.DataBindings.Add("Text", DataSet1.Customers, "CustomerID")

Visual C#

TextBox1.DataBindings.Add("Text", DataSet1.Customers, "CustomerID");

In some cases, you might be binding to an object that doesn t have multiple data members, such as a collection or array. In this case, you should supply an empty string as the third parameter. The following code example demonstrates how to bind a property of a control to an array:

Visual Basic .NET

Dim myStrings(3) As String myStrings(0) = "A" myStrings(1) = "String" myStrings(2) = "Array" TextBox1.DataBindings.Add("Text", myStrings, "")

Visual C#

String[] myStrings = new String[3]; myStrings[0] = "A"; myStrings[1] = "String"; myStrings[2] = "Array"; TextBox1.DataBindings.Add("Text", myStrings, "");

Similarly, to remove a data binding association from a control, you can call the DataBindings.Remove method. This method requires a Binding object as a parameter, which you also can access through the DataBindings property. The following code example demonstrates how to remove data binding from the Text property of a Label object:

Visual Basic .NET

Label1.DataBindings.Remove(Label1.DataBindings("Text"))

Visual C#

Label1.DataBindings.Remove(Label1.DataBindings["Text"]);

Additionally, you can remove all data bindings from a control by calling the Data Bindings.Clear method, as follows:

Visual Basic .NET

Label1.DataBindings.Clear()

Visual C#

Label1.DataBindings.Clear();

Data Currency

Navigation of records and updating of data-bound controls is managed in the data layer. Every data source manages navigation with a CurrencyManager object.

NOTE
In this instance, a data source refers to a one- or two-dimensional store of data, such as a DataTable, a DataView, an array, or a collection. A DataSet, which can contain many DataTables, can thus expose multiple data sources.

The CurrencyManager object keeps track of the current record for a particular data source. There can be multiple data sources in an application at one time, and each data source maintains its own CurrencyManager. Because multiple data sources can be represented on a single form at any given time, each form manages the CurrencyManager objects associated with those data sources through a central object called the BindingContext. The BindingContext organizes and exposes the CurrencyManager objects associated with each data source. Thus, you can use the BindingContext property of each form to manage the position of the current record for each data source. You access a particular currency manager by supplying the BindingContext property with the data source object of the CurrencyManager you want to retrieve. For example:

Visual Basic .NET

Me.BindingContext(DataSet1.Customers)

Visual C#

this.BindingContext[DataSet1.Customers]

When navigating records, the current record can be set by setting the Position property for a particular BindingContext, as shown in the following code examples:

Visual Basic .NET

' The following examples assume a Customers table of a DataSet named ' DataSet1 that is resident on the current Windows form ' Sets the current record to the first record of the data source Me.BindingContext(DataSet1.Customers).Position = 0 ' Advances the current record by one Me.BindingContext(DataSet1.Customers).Position += 1 ' Moves the current record back one Me.BindingContext(DataSet1.Customers).Position = 1 ' Sets the current record to the fifth record in the data source Me.BindingContext(DataSet1.Customers).Position = 4 ' Advances to the last record Me.BindingContext(DataSet1.Customers).Position = _ DataSet1.Tables("Customers").Rows.Count 1

Visual C#

// The following examples assume a Customers table of a DataSet named // DataSet1 that is resident on the current Windows form // Sets the current record to the first record of the data source this.BindingContext[DataSet1.Customers].Position = 0; // Advances the current record by one this.BindingContext[DataSet1.Customers].Position ++; // Moves the current record back one this.BindingContext[DataSet1.Customers].Position ; // Sets the current record to the fifth record in the data source this.BindingContext[DataSet1.Customers].Position = 4; // Advances to the last record this.BindingContext[DataSet1.Customers].Position = DataSet1.Tables["Customers"].Rows.Count 1;

To navigate bound data in a Windows Form

Set the Position property for the appropriate BindingContext member.

Because the .NET Framework will not allow you to set the Position property to a value less than zero or greater than the upper bound of the collection, there is no possibility of an error occurring if you attempt to move before or after the end of the records. You might, however, want to incorporate program logic to provide visual cues to users to let them know when the end or beginning of a group of records is reached. The following code example demonstrates how to use the PositionChanged event of the CurrencyManager to disable back and forward buttons when the end of the record list is reached. As in the previous example, the CurrencyManager is accessed through the form s BindingContext property.

Visual Basic .NET

' This adds a method to handle the PositionChanged event Public Sub OnPositionChanged(ByVal sender As Object, ByVal e As _ System.EventArgs) ' Checks to see if the CurrencyManager is at the start of the ' records If Me.BindingContext(DataSet1, "Customers").Position = 0 Then ' Disables the back button BackButton.Enabled = False Else ' Enables the back button BackButton.Enabled = True End If ' Checks to see if the CurrencyManager is at the end of the records If Me.BindingContext(DataSet1.Customers).Position = _ DataSet1.Tables("Customers").Rows.Count 1 Then ' Disables the forward button ForwardButton.Enabled = False Else ' Enables the forward button ForwardButton.Enabled = True End If End Sub ' You must also hook up the event to the method that is to handle ' it by adding the following line to the Form's constructor. AddHandler Me.BindingContext(DataSet1.Customers).PositionChanged, _ AddressOf Me.OnPositionChanged

Visual C#

// This adds a method to handle the PositionChanged event public void OnPositionChanged(object sender, System.EventArgs e) { // Checks to see if the CurrencyManager is at the start of the // records if (this.BindingContext[DataSet1.Customers].Position == 0) // Disables the back button BackButton.Enabled = false; else // Enables the back button BackButton.Enabled = true; // Checks to see if the CurrencyManager is at the end of the // records if (this.BindingContext[DataSet1.Customers].Position == DataSet1.Tables["Customers"].Rows.Count -1) // Disables the forward button ForwardButton.Enabled = false; else // Enables the forward button ForwardButton.Enabled = true; } // You must also hook up the event to the method that is to handle // it by adding the following line to the Form's constructor this.BindingContext[DataSet1.Customers].PositionChanged += new EventHandler(this.OnPositionChanged);

Complex Binding

Some controls, such as ListBox, ComboBox, or DataGrid can be bound to more than one record at a time. This is called complex binding. Controls such as these are frequently involved in displaying choices and allow the user to select one of many displayed records. You can create a complex-bound control by setting the DataSource property of a control that supports complex binding. For example:

Visual Basic .NET

DataGrid1.DataSource = DataSet1.Customers

Visual C#

DataGrid1.DataSource = DataSet1.Customers;

You can also can create this association at design time by setting the DataSource property in the Properties window.

Controls such as ListBox, CheckedListBox, and ComboBox can display several records at once, but they can be bound to a single column only. For these controls, it is necessary to set the DisplayMember property, which is a string that represents the name of the column to bind to. For example:

Visual Basic .NET

ComboBox1.DataSource = DataSet1.Customers ComboBox1.DisplayMember = "CustomerID"

Visual C#

ComboBox1.DataSource = DataSet1.Customers; ComboBox1.DisplayMember = "CustomerID";

Filtering and Sorting Data

After you have filled a DataSet, you might find it useful to work with a subset of the data in memory. A DataView allows you to work with a subset of the data contained in a DataTable. You can think of a DataView as a filter that sits on top of a DataTable. It screens the data in a DataTable and presents it to the controls that are bound to it. It provides methods for sorting and filtering the data, and allows you to update the DataTable it represents.

Creating a DataView

You can create a new DataView by specifying the DataTable that it will filter. For example:

Visual Basic .NET

Dim myDataView As New DataView(myDataTable)

Visual C#

DataView myDataView = new DataView(myDataTable);

The code in the previous example creates a DataView object that represents the data in myDataTable. The data in this DataView can then be filtered and sorted by setting the DataView properties. You also can create a DataView that is not associated with any DataTable. You will be unable to bind to the DataView until you set the Table property, which is demonstrated as follows:

Visual Basic .NET

Dim myDataView As New DataView() myDataView.Table = myDataTable

Visual C#

DataView myDataView = new DataView(); myDataView.Table = myDataTable;

You can also create a DataView and bind controls to it at design time. To create a DataView object at design time, drag a DataView object from the Toolbox Data tab to the designer and set the Table property in the Properties window. You can then bind controls to this DataView by setting the DataBindings properties in the Properties window.

Filtering and Sorting in a DataSet

DataView objects allow filtering and sorting of the data they expose. Filter and sort conditions can be changed at run time. When the filter or sort criteria for the DataView are changed, any controls bound to the DataView are updated with the new data subset.

Data sorting is accomplished by setting the Sort property. The Sort property takes a string that can be parsed to an expression that describes how to sort the data. Typically, this is the name of a column to sort by. For example:

Visual Basic .NET

myDataView.Sort = "CustomerID"

Visual C#

myDataView.Sort = "CustomerID";

You can sort by more than one column. If more than one column is specified, the column names should be separated by a comma. For example:

Visual Basic .NET

myDataView.Sort = "State, City"

Visual C#

myDataView.Sort = "State, City";

By default, rows are sorted in ascending order. To sort in descending order, append DESC to each column you want to sort in descending order. An example follows:

Visual Basic .NET

' In this example the rows will be sorted by descending state, but ' ascending city, as sorting is ascending unless otherwise marked myDataView.Sort = "State DESC, City"

Visual C#

// In this example the rows will be sorted by descending state, but // ascending city, as sorting is ascending unless otherwise marked myDataView.Sort = "State DESC, City";

You filter data by setting the RowFilter property. The RowFilter property takes a string that can evaluate to an expression to be used for selecting records. For example, you can select only rows that contain a specific value in one column:

Visual Basic .NET

myDataView.RowFilter = "City = 'Seattle'"

Visual C#

myDataView.RowFilter = "City = 'Seattle'";

In general, RowFilter expressions must follow SQL WHERE clause syntax. An overview of this syntax is presented in Lesson 2 of this chapter. String literals within the RowFilter expression must be enclosed in single quotes ( ). If a date is specified, it must be surrounded by the pound (#) symbol.

You can use the logical operators AND, OR, and NOT to build more complex expressions. For instance:

Visual Basic .NET

myDataView.RowFilter = "City = 'Seattle' AND State = 'WA'" myDataView.RowFilter = "City = 'Seattle' OR State = 'WA'" myDataView.RowFilter = "City = 'Des Moines' AND (NOT State = 'IA')"

Visual C#

myDataView.RowFilter = "City = 'Seattle' AND State = 'WA'"; myDataView.RowFilter = "City = 'Seattle' OR State = 'WA'"; myDataView.RowFilter = "City = 'Des Moines' AND (NOT State = 'IA')";

Arithmetic, concatenation, and relational operators can be used to form RowFilter expressions.

Visual Basic .NET

myDataView.RowFilter = "Length >= 10 AND Height < 4" myDataView.RowFilter = "CityState = City + 'WA'" myDataView.RowFilter = "Price * 1.086 <= 500"

Visual C#

myDataView.RowFilter = "Length >= 10 AND Height < 4"; myDataView.RowFilter = "CityState = City + 'WA'"; myDataView.RowFilter = "Price * 1.086 <= 500";

The IN and LIKE operators allow you to search for specific strings as demonstrated:

Visual Basic .NET

myDataView.RowFilter = "City IN ('Seattle', 'Tacoma', Blaine')" ' For string comparisons, * is a wildcard that stands for any single ' character, % stands for any number of any characters. myDataView.RowFilter = "City LIKE 'Seatt%'"

Visual C#

myDataView.RowFilter = "City IN('Seattle', 'Tacoma', Blaine')"; // For string comparisons, * is a wildcard that stands for any single // character, % stands for any number of any characters. myDataView.RowFilter = "City LIKE 'Seatt%'";

In addition, the DataView.RowState property allows you to filter DataRow objects based on their state. Table 6.5 summarizes the possible settings for this property.

Table 6-5. RowState Property Settings

Setting

Description

Unchanged

Displays rows that have not been changed

Added

Displays rows added since the last DataSet update

Deleted

Displays rows that have been deleted since the last DataSet update

OriginalRows

Original rows, including unchanged and deleted rows

CurrentRows

Current rows, including added, modified, and unchanged rows

ModifiedCurrent

A current version, which is a modified version of original data

ModifiedOriginal

The original version (although it has been modified and is available as ModifiedCurrent)

You can set this property to more than one of these values at once. For example, a RowState setting of Added, Deleted would display only rows that have been either newly added or recently deleted.

Editing Data with a DataView

DataView objects expose three properties that determine whether or not the underlying data represented by the DataView can be edited. These properties are summarized in Table 6.6.

Table 6-6. Data Editing Related Properties of the DataView Class

Property

Description

AllowDelete

When this property is set to True (true), the DataView allows deletion of rows from the underlying DataTable.

AllowEdit

When this property is set to True (true), the DataView allows rows of the underlying DataTable to be edited.

AllowNew

When this property is set to True (true), the DataView allows new rows to be added to the underlying DataTable.

By default, DataView objects are fully editable. If you want to make a read-only DataView or a DataView that does not allow adding or deleting rows, you can set any or all of the appropriate properties to False (false).

The DataViewManager class

The DataViewManager class is to the DataSet what the DataView is to the Data Table. An instance of DataViewManager is associated with a DataSet and creates and manages DataView objects for the various tables in that DataSet on demand. You create a new DataViewManager by specifying a DataSet object as a parameter or by setting the DataSet property after the DataViewManager has been created. For example:

Visual Basic .NET

Dim myDataViewManager As New DataViewManager(myDataSet) Dim myOtherDataViewManager As New DataViewManager myOtherDataViewManager.DataSet = myOtherDataSet

Visual C#

DataViewManager myDataViewManager = new DataViewManager(myDataSet); DataViewManager myOtherDataViewManager = new DataViewManager(); myOtherDataViewManager.DataSet = myOtherDataSet;

Once connected to a DataSet, RowFilter, Sort, and other properties can be managed through the DataViewSettings collection. The DataViewSettings property exposes a collection of DataView property values, one for each table in the DataSet. These values are set by specifying which table to set DataView properties for and then specifying the property itself. For example, the following code sample sets the RowFilter property for the DataView associated with the Customers table:

Visual Basic .NET

myDataViewManager.DataViewSettings("Customers").RowFilter = _ "State = 'WA'"

Visual C#

myDataViewManager.DataViewSettings["Customers"].RowFilter = "State = 'WA'";

When needed, DataViews can be retrieved from the DataViewManager by using the CreateDataView method, which requires a reference to a DataTable. An example follows:

Visual Basic .NET

Dim myDataView As DataView myDataView = myDataViewManager.CreateDataView(DataSet1.Tables(0))

Visual C#

DataView myDataView; myDataView = myDataViewManager.CreateDataView(DataSet1.Tables[0]);

Lesson Summary

  • Data binding refers to the relationship between a data provider and a data consumer. Data providers make data available, and data consumers receive data and display or otherwise process it.

  • There are two kinds of data binding: simple binding and complex binding. A simple-bound control binds a single record at a time, whereas a complex-bound control binds all available records at once.

  • Data binding for controls is managed through the DataBindings property. Any run-time available property of a control can be bound to a data source.

  • CurrencyManager objects manage data currency. Every data source has an associated CurrencyManager that keeps track of the current record. CurrencyManager objects are in turn managed by the Form.BindingContext property.

  • A DataView is an object that is associated with a DataTable and provides a filterable, sortable subset of the data contained by the underlying table.

  • The RowFilter and Sort properties of DataView objects are used to specify sorting and filtering conditions for a particular DataView object.

  • A DataViewManager manages DataView objects for an entire DataSet. Individual DataView object properties can be set through the DataViewSettings property, and individual DataView objects can be retrieved with the CreateDataView method.



MCAD(s)MCSD Self-Paced Training Kit(c) Developing Windows-Based Applications With Microsoft Visual Basic. Net a[.  .. ]0-316
MCAD(s)MCSD Self-Paced Training Kit(c) Developing Windows-Based Applications With Microsoft Visual Basic. Net a[. .. ]0-316
ISBN: 735619263
EAN: N/A
Year: 2003
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net