Data Binding in ASP.NET
Richard Harris
DevOps, Online & Mobile at TD Bank Group #devops #agile #cloud #java #js #csharp
Overview
Data Binding is an ASP.NET feature that allows you to pop data directly into HTML elements and fully formatted controls.
These notes present a thorough overview of Data Binding in ASP.NET. First, you'll learn an interesting way to create dynamic text with simple data binding. You'll also learn how ASP.NET builds on this infrastructure with much more useful features, including repeated-value binding for quick-and-easy data display in a list control, and data source controls, which let you create code-free bound pages.
Contents
Tutorial
Quick Reference
Examples
1) Simple Data Binding Example - SimpleDataBinding.aspx?
Convert all the data binding expressions on the page via DataBind() method on of?different controls objects (after setting DataSource) or the Page object. You can assign Page class variable values in your code-behind and then call this.DataBind() in Page_Load().
This example uses Simple Data Binding to bind a page class variable and an expression within the aspx via Data Binding Expression (i.e. <%# Var_Prop_Expr %> ).?
Note: Another use of where you would also use a Data Binding Expression is with the Repeater control (Repeated-Value Data Binding).
ASPX:
<!-- We could have used %= instead of %#, and if so then we would not have to call DataBind() -->
There were <%# TransactionCount %> transactions today. <br /><br />
I see that you are using <%# Request.Browser.Browser %>.?
Code-Behind:
public partial class SimpleDataBinding : System.Web.UI.Page
{
protected int TransactionCount;
protected void Page_Load(object sender, EventArgs e)
{
// You could use database code here to look up a value for TransactionCount.
TransactionCount = 10;
// Now convert all the data binding expressions on the page.
this.DataBind();
}
}
2) Simple Data Binding with Control Properties - DataBindingUrl.aspx?
This example demonstrates Simple Data Binding with Page Properties and using this technique to set control properties (i.e. HyperLink.NavigateUrl or Image.ImageUrl).?
We'll create and set Page class variable, then call this.DataBind(). The variable value (a URL) then gets used to set a property within a Label, CheckBox, Hyperlink, and Image control.
ASPX:
<asp:Label id="lblDynamic" runat="server"><%# URL %></asp:Label><br /><br />
<asp:CheckBox id="chkDynamic" Text="<%# URL %>" runat="server" /><br /><br />
<asp:Hyperlink id="lnkDynamic" Text="Click here!" NavigateUrl="<%# URL %>" runat="server" /><br /><br />
<asp:Image id="imgDynamic" ImageUrl="<%# URL %>" runat="server" />
Code-Behind:
public partial class DataBindingUrl : System.Web.UI.Page
{
protected string URL;
protected void Page_Load(Object sender, EventArgs e)
{
URL = "Images/picture.jpg";
this.DataBind();
}
}
3) A Simple List Binding Example - ListDataBinding.aspx?
In this example, we'll populate a List<string> collection, then set it as the DataSource for the List controls.?Then DataBind the page.
Note: DataTextField & DataValueField are key properties of List controls.?
ASPX:
<h3>ListBox</h3>
<asp:ListBox id="MyListBox" runat="server"></asp:ListBox><br /><br />
<h3>HtmlSelect</h3>
<select id="MyHTMLSelect"? size="1"? runat="server"/><br /><br />
<h3>DropDownList</h3>
<asp:DropDownList id="MyDropDownListBox" runat="server"></asp:DropDownList><br /><br />
<h3>CheckBoxList</h3>
<asp:CheckBoxList id="MyCheckBoxList"? runat="server"></asp:CheckBoxList><br /><br />
<h3>RadioButtonList</h3>
<asp:RadioButtonList id="MyRadioButtonList" runat="server"></asp:RadioButtonList>
Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
// Create and fill the collection.
List<string> fruit = new List<string>();
fruit.Add("Strawberry");
fruit.Add("Banana");
fruit.Add("Blueberry");
fruit.Add("Peach");
fruit.Add("Pear");
// Define the binding for the list controls.
// Note: List is straightforward.? If you were using a DataTable or DataSet,?
// you would have to specify additional information (i.e. .DataSource = ds.Tables[0]), as seen in:?
// https://aspsnippets.com/Articles/Bind-Populate-ASPNet-DropDownList-using-DataTable-DataSet-in-C-and-VBNet.aspx
MyListBox.DataSource = fruit;
MyHTMLSelect.DataSource = fruit;
MyDropDownListBox.DataSource = fruit;? ? ? ??
MyCheckBoxList.DataSource = fruit;
MyRadioButtonList.DataSource = fruit;
// Activate the binding.
this.DataBind();
}
Note: In the example above, the collection is created manually just before it's displayed.?In a more realistic application, however, you might be using a function that returns a ready-made collection to you.?
List<string> fruit = GetFruitsInSeasons("Summer");
lstItems.DataSource = fruit;
this.DataBind();
4) Data Binding with a Dictionary - DictionaryCollection.aspx
In this example, we'll create a Dictionary collection with an integer key and string value (Dictionary<int, string> fruit), then Bind it to a ListBox (DataTextField & DataValueField).
We'll utiize the ListControl properties DataTextField & DataValueField, which we'll set to "Value" and "Key" of the Dictionary object respectively. Note, before doing so, we'll set ListControl DataSource property to our Dictionary object.
Note: Each item in a Dictionary-style collection has both a key and a value associated with it. If you don’t specify which property you want to display, ASP.NET simply calls the ToString() method on each collection item (we assign DataTextField & DataValueField otherwise the result is the key and the value in square brackets).?
ASPX:
<asp:ListBox ID="MyListBox" runat="server" AutoPostBack="True" OnSelectedIndexChanged ="MyListBox_SelectedIndexChanged" ></asp:ListBox>
<asp:Label ID="lblMessage" runat="server" Font-Bold="True"></asp:Label>
Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
// The technique in this example is particularly useful with a database.You could embed a unique ID into the value property?
// and be able to quickly look up a corresponding record depending on the user’s selection by examining the value of the SelectedItem object.?
// Note that for this to work, you can’t regenerate the list after every postback.If you do, the selected item information will be lost and an error will occur.
if (!this.IsPostBack)
{
Dictionary<int, string> fruit = new Dictionary<int, string>();? ?
fruit.Add(1, "Kiwi");
fruit.Add(2, "Pear");
fruit.Add(3, "Mango");
fruit.Add(4, "Blueberry");
// Define the binding for the list controls.
MyListBox.DataSource = fruit;
// When DataBinding to a Dictionary collection, you might use the DataTextField & DataValueField of your List Control,?
// and set them to the "Value" and "Key" of the Dictionary object respectively:
// Choose what field to display in the list
MyListBox.DataTextField = "Value";? ??
// Sets value attribute of option tag
MyListBox.DataValueField = "Key";? ??
// Activate the binding.
this.DataBind();
}
}
protected void MyListBox_SelectedIndexChanged(object sender, EventArgs e)
{
lblMessage.Text = "You picked: " + MyListBox.SelectedItem.Text;
lblMessage.Text += " which has the key: " + MyListBox.SelectedItem.Value;?
}
5) Data Binding with a DataSet - DataSetBinding.aspx ?
This example creates a DataSet (create DataSet & DataTable, add DataColumn objects, add DataRows) by hand and Binds it to a list.
We'll set DataSource of the ListBox to the DataTable within the Dataset, and set the DataTextField and DataValueFields to Columns of that DataTable.
ASPX:
<asp:ListBox ID="lstUser" runat="server" OnSelectedIndexChanged ="lstUser_SelectedIndexChanged" AutoPostBack="True"></asp:ListBox>
<br />
<asp:Label ID="lblMessage" runat="server" Text="Select User"></asp:Label>
Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
if(!this.IsPostBack) // needed, otherwise you won't be able to capture which ListBox item gets selected
{
// Define a DataSet with a single DataTable.
// 1 - Create DataSet
DataSet dsInternal = new DataSet();
// 2 - Create DataTable
dsInternal.Tables.Add("Users");
// 3 - Define structure by adding DataColumn objects
dsInternal.Tables["Users"].Columns.Add("Name");? ? ? ? ?
dsInternal.Tables["Users"].Columns.Add("Country");
// Add some actual information into the table.
// 4 - Create DataRow objects
// - NewRow() creates a new blank row that has the same structure as your DataTable
// - Set the data in all fields
// - Add to the DatatTable.Rows collection
DataRow rowNew = dsInternal.Tables["Users"].NewRow();? ?
rowNew["Name"] = "John";? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
rowNew["Country"] = "Uganda";
dsInternal.Tables["Users"].Rows.Add(rowNew);? ? ? ? ? ??
rowNew = dsInternal.Tables["Users"].NewRow();
rowNew["Name"] = "Samantha";
rowNew["Country"] = "Belgium";
dsInternal.Tables["Users"].Rows.Add(rowNew);
rowNew = dsInternal.Tables["Users"].NewRow();
rowNew["Name"] = "Rico";
rowNew["Country"] = "Japan";
dsInternal.Tables["Users"].Rows.Add(rowNew);
// 5 - Bind the DataTable from the DataSet to the control
// Define the binding. (method #1)
lstUser.DataSource = dsInternal.Tables["Users"];? ? ? ?
lstUser.DataTextField = "Name"; // DataTable has multiple fields, List control can only display one, so set DataText field
lstUser.DataValueField = "Country";
// Alternatively, you could use the entire DataSet for the data source, instead of just the appropriate table.
// In that case, you would have to select a table by setting the control's DataMember Property.
// Define the binding. (method #2)
// lstUser.DataSource = dsInternal;?
// lstUser.DataMember = "Users";
// 6 - Activate binding?
this.DataBind(); // alternative: lstItems.DataBind() to bind just the list box.? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
}
}
protected void lstUser_SelectedIndexChanged(object sender, EventArgs e)
{
lblMessage.Text = "You picked: " + lstUser.SelectedItem.Text;
lblMessage.Text += " which has the key: " + lstUser.SelectedItem.Value;? ?// *
}
6) Creating a Record Editor (Label to display + ListBox to select + Button to update) - RecordEditor.aspx
This example is a Record Editor that includes a DropDownList of Products, a?Label to display the selected Product's Details, and a ListBox to update the Product's Category property. It combines knowledge of SqlClient (Update button) & Data Binding (Data-Bound List controls) and is a practical example of how you might use Data Binding in a full ASP.NET application.?
The SqlCommand (within the lstProduct_SelectedIndexChanged event handler method) used to retrieve the Product details uses Parameters and a SQL Join query (to get Categories.CategoryName).??
Flow of application:
Note: The Product list population in Page_Load does not need to use Parameters because it does not use User input.?
Note: This example uses ADO.NET's SqlClient namespace and Data Binding, but opts not to use use Data Controls (e.g. SqlDataSource) to populate the List controls (see #7).
ASPX:
<!-- Note the use of DropDownList AutoPostBack property -->?
<asp:DropDownList ID="lstProduct" runat="server" AutoPostBack="True" OnSelectedIndexChanged ="lstProduct_SelectedIndexChanged">
</asp:DropDownList><br /><br />
<asp:Panel ID="pnlDetails" runat="server" Visible="False">
<table>
<tr>
<td valign="top">
<asp:Label ID="lblRecordInfo" runat="server"></asp:Label>
</td>
<td>
<asp:ListBox ID="lstCategory" runat="server"></asp:ListBox>
<br /><br />
<asp:Button ID="cmdUpdate" runat="server" Text="Update Category" OnClick ="cmdUpdate_Click" />
</td>
</tr>
</table>
</asp:Panel>
Code-Behind:
public partial class RecordEditor : System.Web.UI.Page
{
private string connectionString = WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
protected void Page_Load(object sender, EventArgs e)
{
// The list is only filled the first time the page is requested and stored in view state automatically
if (!this.IsPostBack)?
{
// Populate a DropDownList using an SqlDataReader
// Note: In a real application, you'd need to use exception handling
// Define the ADO.NET objects for selecting Products.
string selectSQL = "SELECT ProductName, ProductID FROM Products"; // only retrieve the data we'll use
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(selectSQL, con);
// Open the connection.
con.Open();
// Define the binding.
lstProduct.DataSource = cmd.ExecuteReader(); // notice no explicit SqlDataReader object?
lstProduct.DataTextField = "ProductName";
lstProduct.DataValueField = "ProductID";
// Activate the binding.
lstProduct.DataBind(); // calls DataBind on the controls, not the page
// Close the connection.
con.Close();
// Note: Alternatively refer to Example #8 which shows?
//an alterative way to do this (via DropDownList.AppendDataBoundItems)
lstProduct.Items.Insert(0, "---- Select Product -----");?
// Make sure nothing is currently selected.
lstProduct.SelectedIndex = -1;
}
}
protected void lstProduct_SelectedIndexChanged(object sender, EventArgs e)
{
if (lstProduct.SelectedIndex == 0) // "---- Select Product -----"
return;
/* Retrieve the Product Record */
// Create a command for selecting the matching product record.
// Note: Usage of Join query
string selectProduct = "SELECT ProductName, QuantityPerUnit, " +
"CategoryName FROM Products INNER JOIN Categories ON " +? ?
"Categories.CategoryID=Products.CategoryID " +
"WHERE ProductID=@ProductID";
// Create the Connection and Command objects.
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmdProducts = new SqlCommand(selectProduct, con);
cmdProducts.Parameters.AddWithValue("@ProductID", lstProduct.SelectedItem.Value);
// Retrieve the information for the selected product.
using (con)
{
con.Open();
SqlDataReader reader = cmdProducts.ExecuteReader();
reader.Read();
// Update the display.
lblRecordInfo.Text = "<b>Product:</b> " + reader["ProductName"] + "<br />";
lblRecordInfo.Text += "<b>Quantity:</b> " + reader["QuantityPerUnit"] + "<br />";
lblRecordInfo.Text += "<b>Category:</b> " + reader["CategoryName"];
// Store the corresponding CategoryName for future reference.
string matchCategory = reader["CategoryName"].ToString();
// Close the reader.
reader.Close();
/* Retrieve all the Categories, then Select the Product's Category */
// Note: We could move this code to be in Page_Load, but would need to add?
// code to close SqlDataReader and wanted to show that we didn't use an?
// explicit SqlDataReader object (also also seen below)
// Create a new Command for selecting categories.
string selectCategory = "SELECT CategoryName, CategoryID FROM Categories";
SqlCommand cmdCategories = new SqlCommand(selectCategory, con);
// Retrieve the category information, and bind it.
lstCategory.DataSource = cmdCategories.ExecuteReader();
lstCategory.DataTextField = "CategoryName";
lstCategory.DataValueField = "CategoryID";
lstCategory.DataBind();
// Highlight the matching category in the list.
lstCategory.Items.FindByText(matchCategory).Selected = true;? ?
}
pnlDetails.Visible = true;
}
protected void cmdUpdate_Click(object sender, EventArgs e)
{
// Define the Command.
string updateCommand = "UPDATE Products " +
"SET CategoryID=@CategoryID WHERE ProductID=@ProductID";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(updateCommand, con);
cmd.Parameters.AddWithValue("@CategoryID", lstCategory.SelectedItem.Value);
cmd.Parameters.AddWithValue("@ProductID", lstProduct.SelectedItem.Value);
// Perform the update.
using (con)
{
con.Open();
cmd.ExecuteNonQuery();
}
}
}
Tip: This example doesn't attempt to deal with errors.?In a real application, you'd need to use the exception handling approach.?
Note: The query used in this example to display Product details uses a database table join in order to include Category Name (Product table only has CategoryID)
SELECT ProductName, QuantityPerUnit, CategoryName?
FROM Products INNER JOIN Categories?
ON Categories.CategoryID=Products.CategoryID
WHERE ProductID=@ProductID;
Tip: You can select a particular List control ListItem via (e.g. handy when loading a record where the U.I. has one of its properties displayed in a List control):?
lstCategory.Items.FindByText("MatchItemText").Selected = true;
Tip: You could improve this code in several ways. It probably makes the most sense to remove these data access routines from the event handler and put them into more generic functions. For example, you could use a function that accepts a ProductID and returns a single DataRow with the associated product information. Another improvement would be to use a stored procedure to retrieve this information.
7) SqlDataSource with Parameters (ControlParameter) for use in SelectCommand & UpdateCommand - RecordEditorDataSource.aspx
In this example we'll create a Record Editor using a DropDownList control (select Product), a DetailsView control (display & update Product details), and two SqlDataSource controls (used by the DropDownList & DetailsView).?This example does not require you to write any C# code!?
First we'll retrieve data based on a DropDownList selection. Then we'll display and make updates via a DetailsView with AutoGenerateEditButton enabled. The SqlDataSource that the DetailsView uses has a Parameterized SelectCommand & UpdateCommand (which uses a ControlParameter that looks at the DropDownList control's selected value).?
Flow of application: SqlDataSource (sourceProducts) ? DropDownList (lstProduct) ? SqlDataSource (sourceProductDetails) ? DetailsView (DetailsView1)
Note: This page allows overlapping edits. See RecordEditorDataSource_MatchAllValues.aspx for a version that doesn't.
ASPX:
<asp:DropDownList ID="lstProduct" runat="server" AutoPostBack="True"?
DataSourceID="sourceProducts" DataTextField="ProductName"?
DataValueField="ProductID" AppendDataBoundItems="True">
<asp:ListItem Value="0">Select Product</asp:ListItem>
</asp:DropDownList>
<asp:SqlDataSource ID="sourceProducts" runat="server" ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>"?
SelectCommand="SELECT ProductName, ProductID FROM Products" />
<br /><br />
<asp:DetailsView ID="DetailsView1" runat="server" DataSourceID="sourceProductDetails" AutoGenerateEditButton="True">
</asp:DetailsView>
<asp:SqlDataSource ID="sourceProductDetails" runat="server" ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>"?
SelectCommand="SELECT ProductID, ProductName, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued?
FROM Products WHERE ProductID=@ProductID"
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=CONVERT(money, @UnitPrice), UnitsInStock=@UnitsInStock,?
UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel, Discontinued=@Discontinued WHERE ProductID=@ProductID">
<SelectParameters>
<asp:ControlParameter ControlID="lstProduct" Name="ProductID" PropertyName="SelectedValue" />
</SelectParameters>
</asp:SqlDataSource>
Note: This example does not have any Code-Behind (empty .cs file)!?
Tip: You can add a "(Select)" item to your DropDownList by setting DropDownList.AppendDataBoundItems="True" and adding an asp:ListItem within your asp:DropDownList.
8) SqlDataSource with Error Handling that includes setting Parameter value set in code-Behind (SqlDataSource Selecting event) and displays a read-Only GridView - CustomParameters.aspx
In this example, Users start by selecting a Customer record from a DropDownList. We'll then display the associated Order records in a GridView underneath. We'll use two SqlDataSource controls, the 2nd having a ControlParameter (for CustomerID) and a second Parameter.?
When the User picks a customer from the list, the page is posted back (ListBox.AutoPostBack="True") and the matching orders are shown in a GridView underneath, using a second data source. This data source pulls the CustomerID for the currently selected customer from the DropDown list using a ControlParameter (like the in the previous example).
In the code-behind, while'll add handler methods for the Selecting and Selected events of the Order SqlDataSource. Within the Selecting handler we'll set a SqlDataSource Parameter value and and within Selected we'll catch any Exception errors.?
The key part of this is example is the addition of Error Handling for the SqlDataSource via its Selected event.
Flow of application: SqlDataSource (sourceCustomers) ? DropDownList (lstCustomers) ? SqlDataSource (sourceOrders) ? gridOrders
Note: This example is similar to RecordEditorDataSource.aspx (above) except top DropDownown displays Customers (instead of Products) and bottom control is a GridView that shows Orders (instead of DetailsView that shows Product record).
Tip: AllowSorting is a useful property of the GridView control.?
ASPX:
<asp:DropDownList ID="lstCustomers" runat="server" AutoPostBack="True" AppendDataBoundItems="True"
DataSourceID="sourceCustomers" DataTextField="ContactName" DataValueField="CustomerID">
<asp:ListItem Value="0">Select Customer</asp:ListItem>
</asp:DropDownList>
<asp:SqlDataSource ID="sourceCustomers" runat="server"
? ProviderName="System.Data.SqlClient"?
? ConnectionString="<%$ ConnectionStrings:Northwind %>"
? SelectCommand="SELECT CustomerID, ContactName FROM Customers" />
<br /><br />
<asp:GridView ID="gridOrders" runat="server" DataSourceID="sourceOrders"?
AutoGenerateColumns="False" DataKeyNames="OrderID" AllowSorting="true">
<Columns>
<asp:boundfield DataField="OrderID" HeaderText="OrderID" InsertVisible="False"?
ReadOnly="True" SortExpression="OrderID"></asp:boundfield>
<asp:boundfield DataField="OrderDate" HeaderText="OrderDate" DataFormatString="{0:d}"
SortExpression="OrderDate"></asp:boundfield>
<asp:boundfield DataField="ShippedDate" DataFormatString="{0:d}"??
HeaderText="ShippedDate"?
SortExpression="ShippedDate"></asp:boundfield>
</Columns>
</asp:GridView>
<!-- Note: Parameter value modified & Error handling added in Code-Behind -->
<asp:SqlDataSource ID="sourceOrders" runat="server"
ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT OrderID,OrderDate,ShippedDate FROM Orders WHERE CustomerID=@CustomerID AND OrderDate>=@EarliestOrderDate"
OnSelecting ="sourceOrders_Selecting" OnSelected ="sourceOrders_Selected">
<SelectParameters>
<asp:ControlParameter Name="CustomerID" ControlID="lstCustomers" PropertyName="SelectedValue" />
<asp:Parameter Name="EarliestOrderDate" DefaultValue="1900/01/01" />
</SelectParameters>
</asp:SqlDataSource>
<!-- Error Handling Message -->
<asp:Label ID="lblError" runat="server" ForeColor="Red"></asp:Label>
Code-Behind:
// The SqlDataSource Selecting event (OnSelecting handler) can be used to modify Parameters (further results filtering)
protected void sourceOrders_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
// SqlDataSource SelectCommand has OrderDate>=@EarliestOrderDate
// but don't apply the line below because Northwind data has old dates
e.Command.Parameters["@EarliestOrderDate"].Value = DateTime.Today.AddYears(-10);
}
// Handling Errors - The Selected event can be used to handle SqlDataSource errors
protected void sourceOrders_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
lblError.Text = "An exception occurred performing the query.";
// Consider the error handled
e.ExceptionHandled = true;
}
}
9) Updating, Deleting, and Inserting records using a DetailsView and corresponding SqlDataSource Commands - UpdateDeleteInsert.aspx
In this example, we'll use a DetailsView control with Paging?and Auto Generated Buttons to show multiple fields in a Data Source. When using a DetailsView, you can give Users a way to update values by simply setting the AutoGenerateEditButton property to true.?To enable deleting and inserting, you need to set the AutoGenerateDeleteButton and AutoGenerateInsertButton properties to true.
When using a SqlDataSource, you define the InsertCommand, DeleteCommand, and UpdateCommand in the same way you define the command for the SelectCommand property—by using a parameterized query.
DetailsView has built-in tabular rendering, whereas FormView requires user-defined template for its rendering.?They are similar (both display a single data item and enable edit, insert, and deletion), but the FormView allows for more control over the layout.
When you insert a new record it will be given an automatically generated ID and placed at the end of the table. To see it, jump to the last record (using the paging buttons).
Note: The SqlDataSource used has an SQL statement for all 4 CRUD Operations specified within the appropriate properties - SelectedCommand, UpdateCommand, DeleteCommand, and InsertCommand?(the previous examples only had 1 or 2 of these defined).?
Note: The DetailsView in this example has the DataKeyNames and AllowPaging properties defined.
ASPX:
<asp:SqlDataSource ID="sourceProducts" runat="server" ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>"?
SelectCommand="SELECT ProductID, ProductName, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM Products"
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=CONVERT(money, @UnitPrice), UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel, Discontinued=@Discontinued WHERE ProductID=@ProductID"
DeleteCommand="DELETE Products WHERE ProductID=@ProductID"?
InsertCommand="INSERT INTO Products (ProductName, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued) VALUES (@ProductName, CONVERT(money, @UnitPrice), @UnitsInStock, @UnitsOnOrder, @ReorderLevel, @Discontinued)">
</asp:SqlDataSource>
<asp:DetailsView ID="DetailsView1" runat="server"?
DataSourceID="sourceProducts" DataKeyNames="ProductID" AllowPaging="True"?
AutoGenerateInsertButton="true" AutoGenerateDeleteButton="true" AutoGenerateEditButton="true">
<PagerSettings PageButtonCount="25" />
</asp:DetailsView>
Note: This example does not have any Code-Behind (empty .cs file)!?
领英推荐
10) Concurrency Checking - SqlDataSource with match-all-values concurrency (w/ OldValuesParameterFormatString, ConflictDetection, and OnUpdated) + DetailsView (w/ AutoGenerateEditButton) - RecordEditorDataSource_MatchAll.aspx
This example is an enhanced version of the "SqlDataSource with Parameters (ControlParameter)" (RecordEditorDataSource.aspx) example found above.?
This version prevents overlapping edits by implementing Concurrency Checking.
To try this out, open two copies of the page in two browser windows. Start editing the same record in both pages. Make changes in both pages to same field (for example, use two different UnitCost values). Now try applying the changes. The first change will be applied, but the second will fail due to the concurrency conflict.?To replicate this issue, the DetailsView must be in Edit-mode in both windows at the same time, update 1, and then update the other.
Matching every field (e.g. verifying that no column data has been changed within a record while during editing) is an acceptable approach for small records, but it isn’t the most efficient strategy if you have tables with huge amounts of data. You could instead add a timestamp field to your database table, and use that for concurrency checking.
ASPX:
<asp:DropDownList ID="lstProduct" runat="server" AutoPostBack="True"?
DataSourceID="sourceProducts" DataTextField="ProductName"?
DataValueField="ProductID" AppendDataBoundItems="True">
<asp:ListItem Value="0">Select Product</asp:ListItem>
</asp:DropDownList>
<asp:SqlDataSource ID="sourceProducts" runat="server" ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>"?
SelectCommand="SELECT ProductName, ProductID FROM Products" />
<br /><br />
<asp:DetailsView ID="DetailsView1" runat="server"?
DataSourceID="sourceProductDetails" AutoGenerateEditButton="True">
</asp:DetailsView>
<asp:SqlDataSource ID="sourceProductDetails" runat="server" ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>" SelectCommand="SELECT ProductID, ProductName, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM Products WHERE ProductID=@ProductID"
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=@UnitPrice, UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel, Discontinued=@Discontinued WHERE ProductID=@ProductID AND ProductName=@original_ProductName AND UnitPrice=@original_UnitPrice AND UnitsInStock=@original_UnitsInStock AND UnitsOnOrder=@original_UnitsOnOrder AND ReorderLevel=@original_ReorderLevel AND Discontinued=@original_Discontinued"
OldValuesParameterFormatString="original_{0}" ConflictDetection="CompareAllValues"
OnUpdated="sourceProductDetails_Updated">
<SelectParameters>
<asp:ControlParameter ControlID="lstProduct" Name="ProductID" PropertyName="SelectedValue" />
</SelectParameters>
</asp:SqlDataSource>
<asp:Label ID="lblInfo" runat="server" EnableViewState="False" Font-Bold="True" ForeColor="#C00000"></asp:Label>
RecordEditorDataSource.aspx vs.?RecordEditorDataSource_MatchAllValues.aspx:
// RecordEditorDataSource.aspx
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=CONVERT(money, @UnitPrice), UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel, Discontinued=@Discontinued?
WHERE ProductID=@ProductID">
// RecordEditorDataSource_MatchAllValues.aspx - extended WHERE clause and add OldValuesParameterFormatString & ConflictDetection to match all values, and handle error in OnUpdated event handler
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=@UnitPrice, UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel, Discontinued=@Discontinued?
WHERE ProductID=@ProductID?
AND ProductName=@original_ProductName AND UnitPrice=@original_UnitPrice AND UnitsInStock=@original_UnitsInStock AND UnitsOnOrder=@original_UnitsOnOrder AND ReorderLevel=@original_ReorderLevel AND? Discontinued=@original_Discontinued"
OldValuesParameterFormatString="original_{0}" ConflictDetection="CompareAllValues"
OnUpdated ="sourceProductDetails_Updated">
Note: Notice the use of OldValuesParameterFormatString & ConflictDetection properties.?
Code-Behind:
// Handling Errors - check # records affected (0 indicates an error)
protected void sourceProductDetails_Updated(object sender, SqlDataSourceStatusEventArgs e)
{
if (e.AffectedRows == 0)
{
lblInfo.Text = "No update was performed. A concurrency error is likely, or the command is incorrectly written.";
}
else
{
lblInfo.Text = "Record successfully updated.";
}
}
11) Bonus - The Repeater Control
ASPX:
<asp:Repeater ID="rpCountries" runat="server">
<HeaderTemplate>
<h4>Countries</h4>
<ul>
</HeaderTemplate>
<ItemTemplate><li><%#Eval("text")%> (<%#Eval("value") %>)</li></ItemTemplate>? ? ? ? ? ??
<AlternatingItemTemplate></AlternatingItemTemplate>? ? ? ? ? ??
<SeparatorTemplate></SeparatorTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>? ? ? ? ? ? ? ??
</asp:Repeater>
Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
// XML
DataSet mycountries_xml = new DataSet();? // Load XML file into a DataSet?
mycountries_xml.ReadXml(MapPath("App_Data/countries.xml"));?
// Repeater
rpCountries.DataSource = mycountries_xml;
rpCountries.DataBind();
}
Reference
Key Tips
lstCategory.Items.FindByText("MatchItemText").Selected = true;
DropDownList1.Items.Insert(0, New ListItem("--Select Customer--", "0"))
Single-Value or "Simple" Data Binding
The difference between <%= and <%# in ASP.NET:
When should I use # and = in ASP.NET controls?
How To
<%# Request.Browser.Browser %>
<%# TransactionCount %>
<asp:Hyperlink id="lnkDynamic" runat="server"
Text="Click here!" NavigateUrl="<%# URL %>" />
Repeated-Value or "List" Data Binding
How To
List<string> fruit = new List<string>();
fruit.Add("Kiwi");
List<string> fruit = GetFruitsInSeasons("Summer");
lstItems.DataSource = fruit;
this.DataBind();
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
Dictionary<int, string> fruit = new Dictionary<int, string>();
fruit.Add(1,"Kiwi");
// add more items
MyListBox.DataSource = fruit; // define binding
MyListBox.DataTextField = "Value"; // choose field to display
MyListBox.DataValueField = "Key"; // set value attribute of option tag
this.DataBind(); // activate binding
}
}
lblMessage.Text = "You picked: " + MyListBox.SelectedItem.Text
+ " which has the key: " + MyListBox.SelectedItem.Value;
Strongly Typed Collections
Data Binding with a Dictionary Collection
Data-Bound Web Server Controls
List controls
Rich Data controls
References
Data Source Controls
Data source controls allow you to create data-bound pages without writing any data access code at all. The Data Source controls include any control that implements the IDataSource interface. The .NET Framework includes the following data source controls (found in the Data tab of the Toolbox in Visual Studio):
Reference
Data source controls turn up in the .aspx markup portion of your web page like ordinary controls. Here’s an example:
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:[NameOfConnectionString] %>" ... />
Data source controls can perform two key tasks:
SqlDataSource
<asp:DropDownList ID="lstCustomers" runat="server" AutoPostBack="True"DataSourceID="sourceCustomers" DataTextField="ContactName" DataValueField="CustomerID">
</asp:DropDownList>
<asp:SqlDataSource ID="sourceCustomers" runat="server" ProviderName="System.Data.SqlClient" ConnectionString="<%$ ConnectionStrings:Northwind %>" SelectCommand="SELECT CustomerID, ContactName FROM Customers" />
<asp:SqlDataSource ID="sourceOrders" runat="server"
?ProviderName="System.Data.SqlClient"
?ConnectionString="<%$ ConnectionStrings:Northwind %>"
?SelectCommand="SELECT OrderID,OrderDate,ShippedDate FROM Orders?
?WHERE CustomerID=@CustomerID AND OrderDate>=@EarliestOrderDate"
?OnSelecting="sourceOrders_Selecting">
?<SelectParameters>
<asp:ControlParameter Name="CustomerID"?
ControlID="lstCustomers" PropertyName="SelectedValue" />
<asp:Parameter Name="EarliestOrderDate" DefaultValue="1900/01/01" />
?</SelectParameters>
</asp:SqlDataSource>
Handling Errors with the SqlDataSource
protected void sourceOrders_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
// Show a more suitable error message
lblError.Text = "An exception occurred performing the query.";
// Consider the error handled
e.ExceptionHandled = true;
}
}
Updating Records using Rich Data Controls
<asp:SqlDataSource ID="sourceProductDetails" runat="server"
ProviderName="System.Data.SqlClient"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT ProductID, ProductName, UnitPrice, UnitsInStock,
UnitsOnOrder, ReorderLevel, Discontinued FROM Products WHERE ProductID=@ProductID"
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=@UnitPrice,
UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel,
Discontinued=@Discontinued WHERE ProductID=@ProductID">
<SelectParameters>
<asp:ControlParameter ControlID="lstProduct" Name="ProductID"
PropertyName="SelectedValue" />
</SelectParameters>
</asp:SqlDataSource>
<asp:DetailsView ID="detailsProduct" runat="server"
DataSourceID="sourceProductDetails" AutoEditGenerateButton="True" />
Strict Concurrency Checking
UpdateCommand="UPDATE Products
SET ProductName=@ProductName, UnitPrice=CONVERT(money, @UnitPrice),
UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder,
ReorderLevel=@ReorderLevel, Discontinued=@Discontinued
WHERE ProductID=@ProductID">
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=@UnitPrice, UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder, ReorderLevel=@ReorderLevel, Discontinued=@Discontinued
WHERE ProductID=@ProductID AND ProductName=@original_ProductName AND UnitPrice=@original_UnitPrice AND UnitsInStock=@original_UnitsInStock AND UnitsOnOrder=@original_UnitsOnOrder AND ReorderLevel=@original_ReorderLevel?
AND Discontinued=@original_Discontinued"
OldValuesParameterFormatString="original_{0}"?
ConflictDetection="CompareAllValues"?
OnUpdated ="sourceProductDetails_Updated">
// A better way to implement concurrency rather than match-all-values
// is to use a timestamp field
UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=@UnitPrice,
UnitsInStock=@UnitsInStock, UnitsOnOrder=@UnitsOnOrder,
ReorderLevel=@ReorderLevel, Discontinued=@Discontinued
WHERE ProductID=@ProductID AND RowTimestamp=@RowTimestamp"
protected void sourceProductDetails_Updated(object sender,SqlDataSourceStatusEventArgs e)
{
if (e.AffectedRows == 0)
{
? ?lblInfo.Text = "No update was performed. " +
? ?"A concurrency error is likely, or the command is incorrectly written.";
}
else
{
? ?lblInfo.Text = "Record successfully updated.";
}
}
Understanding the Page Life Cycle with Data Binding