How to work with bound controls and parameterized queries Based on Murach C# 2015
Bind a combo box to a data source. Synchronize controls and data Applied Applied Format the data in a bound text box by setting the properties for the control. Before all data have been string data -> no formatting needed Bind a combo box to a data source. Synchronize controls and data Use the properties and methods of the BindingSource class to navigate and modify the rows in a dataset. Create and use a parameterized query with a data source.
Customize the appearance and operation of a DataGridView control. Applied cont. Applied Customize a ToolStrip control by adding controls to it, deleting controls from it, and formatting the controls that are on it. Then, code the event handlers for making these controls work. Customize the appearance and operation of a DataGridView control. Use a DataGridView control as part of a Master/Detail form.
Objectives Knowledge Explain why you might want to use code to work directly with the binding source object for a data source. Describe the use of a parameterized query and the ToolStrip control that gets generated for the query.
C:\Murach
Same as in chapter 18. Add new DataSource
Same as in chapter 18. Add new DataSource (cont)
Same as in chapter 18. Add new DataSource (cont)
Same as in chapter 18. Add new DataSource (cont)
Select All Tables And other
Details
BINDING: CustomerMaintenance (not the same as in ch 18) cmb
Customers->Right Click->Data (Preview)
Drag-and-drop Customers
Use Data Bound Items
Other Data Sources->States expand
Other Data Sources->States->Binding
Two Properties (DropDownStyle)
Two Properties (DataBindings -> None)
Run Rearranged
Murach Explanation To start, you’ll need to select the Use Data Bound Items check box to display the binding properties as shown here. Then, you can set these properties. In this figure, the DataSource property of the State combo box is set to statesBindingSource (which points to the States table), the DisplayMember property is set to the StateName column (which provides the full name of the state), and the ValueMember property is set to the StateCode column (which provides the two-letter code for the state). That way, this combo box will list the full name of each state in the visible portion of the combo box. Finally, the SelectedValue property is used to bind the ValueMember property to a column in another data source. In this case, the SelectedValue property is set to the State column of the customersBindingSource. That way, the StateCode column of the States table is bound to the State column of the Customers table. Then, when the data for a customer is displayed, the state that’s selected in the combo box is determined by the State column of the Customers table. Also, if the user selects a different item from the combo box list, the State column in the Customers table is changed to the value selected by the user. In addition to the four properties in the smart tag menu, you may also needto set a couple of other properties when you bind a combo box. In particular, you can set the DropDownStyle property to DropDownList to prevent the user fromentering text into the text portion of the combo box. Then, you can set the Text property in the DataBindings group to None so the application doesn’t bind the value stored in this property to the data source. If this property isn’t set correctly, the combo box won. ’1: work properly. Although you’ve learned only how to bind combo boxes in this topic, you should realize that you can use similar skills to work with other types of controls. In particular, you can use most of these skills to work with list boxes. If you experiment with this on your own, you shouldn’t have any trouble figuring out how it works.
Combo box properties for binding To set the DataSource property, display the drop-down list; expand the Other Data Sources node, the Project Data Sources node, and the node for the dataset; and select the table you want to use as the data source. This adds BindingSource and TableAdapter objects for the table to the form. Then, you can set the DisplayMember and ValueMernber properties to columns in this table. The SelectedValue property is typically bound to a column in the main table. That way, if you select a different item from the combo box, the value of this column is set to the value of the ValueMember property for the selected item. When you bind a combo box to a data source, you’ll typically set the DropDownStyle property of the combo box to DropDownList so the user can onlyselect a value from the list. You’ll also want to change the (DataBindings) – Text property to None to remove the binding from the text box portion of the combo box.
FORMATTING. The dialog box for formatting a column 1 3 2
The dialog box for formatting a column 5 4
NAVIGATOR: Navigator and Binding Source When you use the binding navigator toolbar to work with a data source, it works by using properties and methods of the BindingSource object. In the two applications presented in chapter 18, for example, you saw that the code that’s generated for the Save button of this toolbar calls the EndEdit method of the binding source to end the current edit operation. Because you don’t have control over most of the code that’s executed by the binding navigator toolbar, though, you may sometimes want to work with the binding source directly.
Working Directly with BindingSource (Common Properties and Methods) Allows to modify rows All is synchronized -> controls shows the current values No Start Edit available (no explicit start) Position allows to set and get
Examples: this.customersBindingSource.AddNew(); A statement that adds a new row to a data source this.customersBindingSource.AddNew(); A statement that saves the changes to the current row and ends the edit this.customersBindingSource.EndEdit(); A statement that cancels the changes to the current row this.customersBindingSource.CancelEdit(); A statement that removes the current row from a data source this.customersBindingSource.RemoveCurrent();
Code that moves to the next row and displays the position and count private void btnNext_Click(object sender, EventArgs e) { this.customersBindingSource.MoveNext(); int position = customersBindingSource.Position + 1; txtPosition.Text = position + " of " + customersBindingSource.Count; } The binding source ensures that all controls that are bound to the same data table are synchronized. That way, when you move to another row, the data-bound controls will display the values in that row. If a form provides for updating the rows in a data table, moving from one row to another causes any changes made to the current row to be saved to the data table. When you add a new row using the AddNew method, the Position property of the binding source is set to one more than the position of the last row in the datatable. You can use the EndEdit and CancelEdit methods to save or cancel the changes to an existing row or a new row that was added using the AddNew method.
Parameterized Query Can select as many rows as needed (otherwise it can be too many, like it was in ch.18) Use Smart Tag
Creating Parametrized Query Move down
The Customer Maintenance form with a toolbar Auto-created toolStrip You can add a parameterized query to a data table using the Search Criteria Builder dialog box. To display this dialog box, display the smart tag menu for a control that’s bound to the data table and then select the Add Query command. When you finish specifying the query in the Search Criteria Builder dialog box, Visual Studio automatically adds a toolbar to your form. This toolbar contains the text boxes that let the user enter the parameters that are needed by the query, and it contains a button that lets the user execute the query. You can add more than one parameterized query to a data table using the Search Criteria Builder. Each query you add is displayed in its own toolbar. Because of that, you may want to modify one of the toolbars so it provides for all the queries.
The generated code for a parameterized query private void fillByCustomerIDToolStripButton_Click(object sender, EventArgs e) { try this.customersTableAdapter.FillByCustomerID(this.mMABooksDataSet.Customers, ((int)(System.Convert.ChangeType(customerIDToolStripTextBox.Text, typeof(int))))); } catch (System.Exception ex) System.Windows.Forms.MessageBox.Show(ex.Message);
The same code after it has been improved private void fillByCustomerIDToolStripButton_Click(object sender, EventArgs e) { try int customerID = Convert.ToInt32( customerIDToolStripTextBox.Text); this.customersTableAdapter.FillByCustomerID( this.mMABooksDataSet.Customers, customerID); if (customersBindingSource.Count == 0) MessageBox.Show("No customer found with this ID. " + "Please try again.", "Customer Not Found"); } catch (FormatException) MessageBox.Show("Customer ID must be an integer.", "Entry Error"); catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString()); using System.Data.SqlClient;
The syntax of the method for filling a table using a parameterized query tableAdapter.QueryName(dataSet.TableName,param1[,param2]...) //MMABooksDataSet.Designer.cs [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")] [global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter")] [global::System.ComponentModel.DataObjectMethodAttribute(global::System.ComponentModel.DataObjectMethodType.Fill, false)] public virtual int FillByCustomerID(MMABooksDataSet.CustomersDataTable dataTable, int CustomerID) { this.Adapter.SelectCommand = this.CommandCollection[5]; this.Adapter.SelectCommand.Parameters[0].Value = ((int)(CustomerID)); if ((this.ClearBeforeFill == true)) { dataTable.Clear(); } int returnValue = this.Adapter.Fill(dataTable); return returnValue;
Conclusion When you finish specifying a query in the Search Criteria Builder dialog box, Visual Studio automatically generates the code that uses the appropriate method to fill the table in the dataset when the user clicks the button in the toolbar. If necessary, you can modify the generated code to make it easier to read or to change the way it works.
The Items Collection Editor for a ToolStrip control For More Complex Queries Add buttons, textboxes etc. Also, ToolStrip Control is generated when Data Source is dragged and dropped (can be used and modified) Note, the binding navigator toolbar that gets generated when you drag a data source onto a form is a customized ToolStrip control. As a result, you can work with this toolbar just as you would any other ToolStrip control. If, for example, a form won’t provide for inserts, updates, and deletes, you can remove the Add, Delete, and Save buttons from this toolbar. You can also add controls that perform customized functions.
The Items Collection Editor for a ToolStrip control (for More Complex Queries) cont. 1 2 3
Common properties of ToolStrip items Because BindingNavigator IS a ToolStrip Control, you can use Items Collection Editor to work with it like any other ToolStrip control
Customized toolbars (Add Cancel Button) Change look-and-feel Add Cancel Button (bindingNavigatorCancelItem). Change DisplayStyle to Text Add Event Handler (double click)
Customized toolbars (Add Cancel Button) Also change text private void bindingNavigatorCancelItem_Click(object sender,EventArgs e) { this.customersBindingSource.CancelEdit(); }
Get All Customers
The event handler for the Get All Customers ToolStrip button Added and named, add Event private void fillToolStripButton_Click(object sender, EventArgs e) { try { this.customersTableAdapter.Fill(this.mMABooksDataSet.Customers); } catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString());
The event handler for the Get All Customers ToolStrip button cont Added a New Custmer
The code for the Customer Maintenance application (more efficient than load all Customer) private void Form1_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the 'mMABooksDataSet.States' table. You can move, or remove it, as needed. this.statesTableAdapter.Fill(this.mMABooksDataSet.States); // TODO: This line of code loads data into the 'mMABooksDataSet.Customers' table. You can move, or remove it, as needed. this.customersTableAdapter.Fill(this.mMABooksDataSet.Customers); } Inefficient on load Better private void Form1_Load(object sender, EventArgs e) { try this.statesTableAdapter.Fill(this.mMABooksDataSet.States); stateComboBox.SelectedIndex = -1; } catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString());
The code for the application (cont The code for the application (cont.) fillByCustomerIDToolStripButton_Click enhanced private void fillByCustomerIDToolStripButton_Click(object sender, EventArgs e) { try int customerID = Convert.ToInt32( customerIDToolStripTextBox.Text); this.customersTableAdapter.FillByCustomerID( this.mMABooksDataSet.Customers, customerID); if (customersBindingSource.Count == 0) MessageBox.Show("No customer found with this ID. " + "Please try again.", "Customer Not Found"); } catch (FormatException) MessageBox.Show("Customer ID must be an integer.", "Entry Error"); catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString());
The code for the application (cont.) (this was already covered) private void bindingNavigatorCancelItem_Click(object sender,EventArgs e) { this.customersBindingSource.CancelEdit(); }
The code for the application (cont.) private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e) { if (customersBindingSource.Count > 0) if (IsValidData()) try this.customersBindingSource.EndEdit(); this.tableAdapterManager.UpdateAll(this.mMABooksDataSet); } catch (ArgumentException ex) MessageBox.Show(ex.Message, "Argument Exception"); customersBindingSource.CancelEdit(); catch (DBConcurrencyException) MessageBox.Show("A concurrency error occurred. " + "Some rows were not updated.", "Concurrency Exception"); this.customersTableAdapter.Fill(this.mMABooksDataSet.Customers); catch (DataException ex) MessageBox.Show(ex.Message, ex.GetType().ToString()); catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString()); At least one row
The code for the application (cont The code for the application (cont.) customersBindingNavigatorSaveItem_Click The row that was retrieved is deleted. No validation needed. else //customersBindingSource.Count == 0 { try this.tableAdapterManager.UpdateAll(this.mMABooksDataSet); } catch (DBConcurrencyException) MessageBox.Show("A concurrency error occurred. " + "Some rows were not updated.", "Concurrency Exception"); this.customersTableAdapter.Fill(this.mMABooksDataSet.Customers); catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString());
The code for the application (cont.) public bool IsValidData() { return IsPresent(nameTextBox, "Name") && IsPresent(addressTextBox, "Address") && IsPresent(cityTextBox, "City") && IsPresent(stateComboBox, "State") && IsPresent(zipCodeTextBox, "Zip code"); }
Validation public bool IsPresent(Control control, string name) { if (control.GetType().ToString() == "System.Windows.Forms.TextBox") TextBox textBox = (TextBox)control; if (textBox.Text == "") MessageBox.Show(name + " is a required field.", "Entry Error"); textBox.Focus(); return false; } else if (control.GetType().ToString() == "System.Windows.Forms.ComboBox") ComboBox comboBox = (ComboBox)control; if (comboBox.SelectedIndex == -1) comboBox.Focus(); return true;
The code for the application (cont.) (this has been covered) private void fillToolStripButton_Click(object sender, EventArgs e) { try this.customersTableAdapter.Fill(this.mMABooksDataSet.Customers); } catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString());
Second Example. CustomerInvoiceDisplay
DataGridView Invoices Table (drag-and-drop Invoices Table) Note format
The smart tag menu for a DataGridView control (Modifiable) Modify Table (Column Name etc.) 1 2 4 3 Disabled, enable needed Reorder columns
Editing space
Common properties of a column
To format columns: The CellStyle Builder dialog box cont
Format Currency Note format
CustomerInvoiceDisplay2 Master/Detail A form that uses a DataGridView control to display data from a related table Main Table: Customer Related/Detail/Subordinate Table: Invoices 1-many Relations 1. Drag to Form 2. Drag to Form Invoices shown twice Will be added
Master/Detail A form that uses a DataGridView control to display data from a related table. Drag both! Removed ToolStrip Space, C2 Unmodifiable Cannot delete invoices No CustomerID
Run No CustomerID, Re-arranged
Steps: Customer and Invoice Tables Detail View For Customer Table Drag Invoices (from Customer Table) to the Form GridView For Subbordinate Invoce Table FillByCustomerID Query SELECT CustomerID, Name, Address, City, State, ZipCode FROM dbo.Customers WHERE (CustomerID = @CustomerID) 5. FillByCustomerID Query SELECT InvoiceID, CustomerID, InvoiceDate, ProductTotal, SalesTax, Shipping, InvoiceTotal FROM dbo.Invoices 6. Format and Beatify
The Customer Invoices form
The dataset schema
Also, if Using Invoice Separate Table
The code for the Customer Invoices form (Subordinate Detail table is retrieved automatically) This may have some problems private void fillByCustomerIDToolStripButton_Click(object sender, EventArgs e) { try int customerID = Convert.ToInt32( customerIDToolStripTextBox.Text); this.customersTableAdapter.FillByCustomerID( this.mMABooksDataSet.Customers, customerID); if (customersBindingSource.Count > 0) this.invoicesTableAdapter.FillByCustomerID( this.mMABooksDataSet.Invoices, customerID); else MessageBox.Show("No customer found with this ID. " + "Please try again.", "Customer Not Found"); } catch (FormatException) MessageBox.Show("Customer ID must be an integer.", "Entry Error"); catch (SqlException ex) MessageBox.Show("Database error # " + ex.Number + ": " + ex.Message, ex.GetType().ToString()); Using System.Data.SqlClient;
19-1 Add a parameterized query to the Product Maintenance form
19-2 Create a Master/Detail form
Project 4-3 Display customer incidents
Project 4-4 Add customer incidents