DataGrid common concerns solutions hbzxf (A good) http://www.hebcom.net/ Introduction The DataGrid Web server control is a powerful tool for displaying information from a data source It is easy to use;. You can display editable data in a professional-looking grid by setting only a few properties. At the same time, the grid has a sophisticated object model that provides you with great flexibility in how you display the data. This paper addresses some of the questions about customizing grid display that are commonly asked in newsgroups, on Web sites, and in other developer forums. The techniques described here are sometimes quite simple and at other times somewhat involved. in each case, however, they address a question of how to go beyond the basic functionality of . the DataGrid control This paper assumes that you are already familiar with the control -. how to add it to a form and configure it to display data you should also understand how to put a row in the grid into edit mode and other basic tasks. (For) . Details, see DataGrid Web Server Control) Finally, you will find it helpful to know how to work with templates -. Adding template columns to the grid and layout out controls inside a template Windows Forms versus Web Forms DataGrid Control The Web Forms DataGrid control is not the same as the Windows Forms equivalent. It is a common (and not unreasonable) assumption that they are the same control, or at least have identical functionality. However, the entire programming paradigm for Web Forms is quite different from that for Windows Forms. For example, Web Forms Pages Perform A Round Trip to the Server for any processing; They must management;
and so on. Because of these differences, there are also significant differences in their respective controls, including the DataGrid control. As a general rule, the Web Forms DataGrid control includes less built-in functionality. A few examples of differences in the Web Forms DataGrid control are: It does not inherently support master-detail data structures As with other Web server controls, it does not support two-way data binding If you want to update data, you must write code to do this yourself you can... Only Edit One Row At A Time. It Does NOT INHERENTLY Support Sorting, Although IT Raises Events You Can Handle in Order To Sort The Grid Contents. on The Other Hand:
You can bind the Web Forms DataGrid to any object that supports the IEnumerable interface. The Web Forms DataGrid control supports paging. It is easy to customize the appearance and layout of the Web Forms DataGrid control as compared to the Windows Forms one. (Details are provided later in this paper.) Controlling Column width, height, and Alignment By default, the DataGrid control sizes rows and columns to fit the overall height and width that you have assigned to the grid. Within the overall grid width, it sizes columns according to the width of the column heading text. All data is displayed left-justified by default. to control column characteristics, you should turn off auto column generation by setting the AutoGenerateColumns property to false. In fact, you should set this property to true only For short-tercs, Such As Quick Proof-of-Concept Pages Or DemonStrations. For production application, you Should Add Columns Explicitly. The Individual Column Can Be Bound Columns OR template columns. To set the column width, you create a style element for that column and then set the element's Width property to standard units (say, pixels). The following example shows you what the HTML syntax looks like for an ItemStyle element with its Width property set. HeaderText = "Title"> asp: BoundColumn> You can set alignment using the style element, setting it to "Right," "Left," and other values defined in the HorizontalAlign enumeration (In Visual Studio, alignment is available for. individual columns in the Format tab of the grid's Property builder) The following is an example:. } Of course, there is little sense in setting a fixed width in code that you could set at design time. You would normally do this only if you wanted to set the width based on a run-time value. You can set the width of a cell or control in units (typically pixels), but it is not straightforward to translate the length of data - which is simply a character count -. into pixels But the data is available for you to examine when you are creating the item Customizing. Column Layout in Display and Edit Mode By default, the grid displays data in pre-sized columns. When you put a row into edit mode, the control displays text boxes for all editable data, regardless of what data type the data is. If you want to customize the content of a column, make the column a template column. Template columns work like item templates in the DataList or Repeater control, except that you are defining the layout of a column rather than a row. When you define a template column You can Specify The Following Templ ATE TYPES: The ItemTemplate allows you to customize the normal display of the data. The EditItemTemplate allows you to specify what shows up in the column when a row is put into edit mode. This is how you can specify a control other than the default text box for editing . A HeaderTemplate and FooterTemplate allow you to customize the header and footer, respectively. (The footer is only displayed if the grid's ShowFooter property is true.) The following example shows the HTML syntax for a template column that displays Boolean data. Both the ItemTemplate . and EditItemTemplate use a check box to display the value In the ItemTemplate, the check box is disabled so that users do not think they can check it In the EditItemTemplate, the check box is enabled Note in Visual Studio, You CAN Specify A Formatting Expression in The Columns Tab of The Control's Property Builder. Some example formatting strings are listed in the following table For more information, see the topics Formatting Types and BoundColumn.DataFormatString Property in the Visual Studio documentation.Format expressionApplied to this data typeDescriptionPrice:. {0: C} Note the {0} is a zero, not the letter. numeric / decimalDisplays the literal "Price:" followed by numbers in currency format The currency format depends on the culture setting specified via the culture attribute on the Page directive or in the Web.config file.. {0: D4} integer (Can not be . used with decimal numbers) Integers are displayed in a zero-padded field four characters wide {0: N2}.% numericDisplays the number with 2-decimal place precision followed by the literal "%" {0: 000.0}. numeric / decimalNumbers . rounded to one decimal place Numbers less than three digits are zero padded {0: D}. date / datetimeLong date format ( "Thursday, August 06, 1996") Date format depends on the culture settting of the page or the Web.. Config file. {0: D} Date / DateTimeshort Date Format ("12/31/99"). {0: YY-MM-DD} Date / DateTimedate in Numeric Year-Month-Day Format (96-08-06) SHOWING AND HIDING COLMICLY One Way to Have Column Appear Dynamically Is To Create Them At Design Time, and The to Hide Or Show Them as Needed. You Can do this by Setting A Colu mn's Visible property The following example shows how to toggle the visibility of the second column (index 1) of the grid:. 'Visual Basic DataGrid1.Columns (1) .Visible = Not (DataGrid1.Columns (1) .Visible) // C # dataGrid1.columns [1] .visible =! (DataGrid1.columns [1] .visible); Adding Columns Dynamically You can hide and show columns if you know in advance what columns you need. Sometimes, however, you do not know that until run time. In that case, you can create columns dynamically and add them to the grid. To do so, you create an instance of one of the column classes supported by the grid -. BoundColumn, EditCommandColumn, ButtonColumn, or HyperlinkColumn (you can add template columns to the grid, but it is slightly more complex For details, see Creating Web Server. Control Templates Programmatically.) Set the column's properties, and then add it to the grid's Columns collection. The following example shows how to add two bound columns to a grid. 'Visual Basic Private Sub Button1_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click 'Set data-binding properties of the grid DataGrid1.AutoGenerateColumns = False DataGrid1.DataSource = Me.dsBooks1 DataGrid1.DataMember = "Books" DataGrid1.DataKeyField = "bookid"' Add two col umns Dim dgc_id As New BoundColumn () dgc_id.DataField = "bookid" dgc_id.HeaderText = "ID" dgc_id.ItemStyle.Width = New Unit (80) DataGrid1.Columns.Add (dgc_id) Dim dgc_title As New BoundColumn () dgc_title. DataField = "title" dgc_title.HeaderText = "title" DataGrid1.Columns.Add (dgc_title) Me.SqlDataAdapter1.Fill (Me.dsBooks1) DataGrid1.DataBind () End Sub // C # private void Button1_Click (object sender, System.EventArgs e) {DataGrid1.AutoGenerateColumns = false; DataGrid1.DataSource = this.dsBooks1; DataGrid1.DataMember = "Books"; DataGrid1.DataKeyField = "bookid"; // Add two columns BoundColumn dgc_id = new BoundColumn (); dgc_id.DataField = "bookid"; dgc_id.HeaderText = "ID"; dgc_id.ItemStyle.Width = new Unit (80); DataGrid1.Columns.Add (dgc_id); BoundColumn dgc_title = new BoundColumn (); dgc_title.DataField = "title"; dgc_title.HeaderText = "title"; DataGrid1.Columns.Add (dgc_title); this.sqlDataAdapter1.Fill (this.dsBooks1); DataGrid1.DataBind ();} Any time that you add controls to a page dynamically, you have the problem of persistence. dynamically-added controls (or in this case, columns) are not automatically added to the page's view state, so you are obliged to add logic to the page to make sure the columns are available with each round trip. An excellent way to do this is to override the page's LoadViewState method, which gives you an early opportunity to reestablish columns in the DataGrid control. Because the LoadViewState method is called before the Page_Load event is raised, re-adding columns In The LoadViewState Method Assures That They Are Available for Normal Manipulation By the time any event code runs. The following example shows how you would expand the previous example to restore the columns each time the page runs again. As before, the Button1_Click handler adds two columns to the grid. (In this example, the event handler . calls a separate routine called AddColumns to do so) in addition, the page contains a simple Boolean property called DynamicColumnsAdded indicating whether the grid has had columns added; the property persists its value in view state The LoadViewState method first calls the base class'. s LoadViewState method, which extracts view state information and configures controls with it. If columns were previously added to the grid (as per the DynamicColumnsAdded property), the method then re-adds them. 'Visual Basic Private Property DynamicColumnAdded () As Boolean Get If ViewState ( "columnAdded") Is Nothing Then Return False Else Return True End If End Get Set (ByVal Value As Boolean) ViewState ( "columnAdded") = Value End Set End Property Protected Overrides Sub LoadViewState (ByVal savedState As Object) MyBase. LoadViewState (savedState) If Me.DynamicColumnAdded Then Me.AddColums () End If End Sub Private Sub Button1_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click 'Check property to be sure columns are not added more than once If Me.DynamicColumnAdded Then Return Else Me.AddColums () End If End Sub Protected Sub AddColums () 'Add two columns Dim dgc_id As New BoundColumn () dgc_id.DataField = "instock" dgc_id.HeaderText = "In Stock DGC_ID .ItemStyle.Width = New Unit (80) DataGrid1.Columns.Add (dgc_id) Dim dgc_title As New BoundColumn () dgc_title.DataField = "title" dgc_title.HeaderText = "Title" DataGrid1.Columns.Add (dgc_title) Me.DataGrid1 .DataBind () Me.DynamicColumnAdded = True End Sub // C # private bool DynamicColumnAdded {get {object b = ViewState [ "DynamicColumnAdded"]; return (b == null) false:? true;} set {ViewState [ "DynamicColumnAdded" ] = value;}} protected override void loadViewState (Object SavedState) {base.loadViewState; if (DynamicColumnAdded) {this.addColumns (); }} Private void Button1_Click (object sender, System.EventArgs e) {if (this.DynamicColumnAdded = true!) {This.AddColumns ();}} private void AddColumns () {BoundColumn dgc_id = new BoundColumn (); dgc_id.DataField = "bookid"; dgc_id.HeaderText = "ID"; dgc_id.ItemStyle.Width = new Unit (80); DataGrid1.Columns.Add (dgc_id); BoundColumn dgc_title = new BoundColumn (); dgc_title.DataField = "title"; dgc_title.HeaderText = "Title"; DataGrid1.Columns.Add (dgc_title); this.sqlDataAdapter1.Fill (this.dsBooks1); DataGrid1.DataBind (); this.DynamicColumnAdded = true;} Adding New Records to a Data Source Using the . DataGrid Control The DataGrid control allows users to view and edit records, but does not inherently include the facility to add new ones However, you can add this functionality in various ways, all of which involve the following: Adding a new, blank record to the data source of the grid (in the dataset or database). If necessary, you will need to assign an ID for the record and put placeholder values into it for any columns can not be null that. Rebinding the DataGrid control to the source. Putting the grid into edit mode for the new record. You need to be able to determine where in the grid the new record appears. Updating the record normally when the user clicks Update, thereby writing the new record to the source with user-provided values. The following example shows the process for adding the new record, binding the grid, and putting it into edit mode. In this example, the data source is a dataset (dsBooks1 or dsBooks1) containing a table called " Books. " 'Visual Basic Private Sub btnAddRow_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAddRow.Click Dim dr As DataRow = Me.DsBooks1.Books.NewRow dr (" title ") =" ( New "DR (" Instock ") = true me.dsbooks1.books.rows.insertat (dr, 0) SE ssion ( "DsBooks") = DsBooks1 DataGrid1.EditItemIndex = 0 DataGrid1.DataBind () End Sub // C # private void btnAddRow_Click (object sender, System.EventArgs e) {DataRow dr = this.dsBooks1.Books.NewRow (); dr ["Title"] = "(new); DR [" instock "] = true; this.dsbooks1.books.rows.Insertat (DR, 0); session [" dsbooks "] = dsbooks1; dataGrid1.edititeMindex = 0 DataGrid1.databind ();} Some Things to NOTES: This code runs when a user clicks an Add button somewhere in the page. The new row is created using the NewRow method. It is then inserted into the dataset table using the InsertAt method, which allows you to place it at a specific, predefined location - in this case, as the first record in the table (that is, the first record in the Rows collection) Alternatively, you could add it to the end of the table, using the row count as the value The important thing is.. that you know exactly where the row is in the table. Because you know that the record is in the first position of the table, you can set the grid's EditItemIndex value to zero to put the new row into edit mode. (If you created the . row elsewhere in the table, you would set EditItemIndex to that location instead) Because you have a new record in the dataset (but not yet in the database), you have to keep a copy of the dataset between round trips - you do not Want to refill it from the database and lose the new record. here, the . Code stores it in Session state You need to reload the dataset from Session state when the page loads The following example shows what your Page_Load handler might look like:. 'Visual Basic Private Sub Page_Load (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load If Me.IsPostBack Then DsBooks1 = CType (Session ( "DsBooks"), dsBooks) Else Me.SqlDataAdapter1.Fill (Me.DsBooks1) Session ( "DsBooks") = DsBooks1 DataGrid1.DataBind ( ) End If End Sub // C # private void Page_Load (object sender, System.EventArgs e) {if (this.IsPostBack) {dsBooks1 = (dsBooks) Session [ "dsBooks"];} else {this.sqlDataAdapter1.Fill (this .dsbooks1); session ["dsbooks"] = dsbooks1; this.DataGrid1.DataBind ();}} For information about maintaining state, see Web Forms State Management in the Visual Studio documentation You can update the record normally For an example, see Walkthrough: Using a DataGrid Web Control to Read and Write.. . Data in the Visual Studio documentation After updating the dataset, update the database, then refresh the dataset Be sure to save the refreshed dataset to Session state again Here is an example of an update handler:.. 'Visual Basic Private Sub DataGrid1_UpdateCommand (ByVal source As Object, _ ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _ Handles DataGrid1.UpdateCommand Dim dr As Dataset.BooksRow 'Get a reference to row zero (where the row was inserted) dr = Me.DsBooks1.Books (0) DIM TB AS TEXTBOX = CTYPE (E.Item.cells (2) .controls (0), TextBox) DR.TITLE = Tb.Text Dim CB as Checkbox = CType (E.Item.cells (3) .controls (1), checkbox) Dr.instock = Cb.checked me.sqldataadapter1.Update (me.dsbooks1) DataGrid1.editIndEx = -1 'Refresh the dataset from the database DsBooks1.Clear () Me.SqlDataAdapter1.Fill (Me.DsBooks1)' Save the refreshed dataset in Session state agin Session ( "DsBooks") = DsBooks1 DataGrid1.DataBind () End Sub // C # private void DataGrid1_UpdateCommand (object source, System.Web.UI.WebControls.DataGridCommandEventArgs e) {dsBooks.BooksRow dr; // Get a reference to row zero (where the row was inserted) dr = this.dsBooks1.Books [0]; TextBox TB1 = (TextBox) E.Item.cells [2] .controls [0]; Dr.Title = tb1.text; checkbox cb = (checkbox) E.Item.cells [3] .controls [1]; Dr.instock = cb.checked; this.sqldataadapter1.Update (this.dsbooks1); dataGrid1.edititemindex = -1; // Refresh the dataset from the database dsBooks1.Clear (); this.sqlDataAdapter1.Fill (this.dsBooks1); // Save the refreshed dataset in Session state agin Session [ "DsBooks"] = dsBooks1; DataGrid1.DataBind (); } Displaying a drop-Down List in Edit Mode A common request is to present users with a drop-down list when a row is in edit mode. For example, the grid might show a list of books, including each book's genre. When users edit a book record, they might want to assign a different genre; ideally, they can select from a drop-down list that shows possible genre values such as "fiction," "biography," or "reference" Displaying a drop-down. list requires a template column in the grid. Typically, the ItemTemplate contains a control such as a data-bound Label control to show the current value of a field in the record. You then add a drop-down list to the EditItemTemplate. in Visual Studio, You CAN Add A Template Column In The Property Builder for the Grid, And Then Use Standard Template Editing T o remove the default TextBox control from the EditItemTemplate and drag a DropDownList control into it instead. Alternatively, you can add the template column in HTML view. After you have created the template column with the drop-down list in it, there are two tasks . The first is to populate the list The second is to preselect the appropriate item in the list -. for example, if a book's genre is set to "fiction," when the drop-down list displays, you often want "fiction" to . be preselected (. Preselecting an item might not be an issue in all scenarios) There are many ways to populate the drop-down list The following examples show you three possibilities:. using static items; using records from a dataset; or by using a data reader to read information directly from a database Static Items To display static items in the drop-down list, you do not data bind the control Instead, you simply define items in the control's.. items collection. in Visual Studio, you can invoke the items collection editor from the items property in the Properties window. Alternatively, you can add items in HTML view. The following shows a complete column definition for a template column that displays the genre in display . mode, and a static list of genre types in edit mode The ItemTemplate contains a Label control whose Text property is bound to the "genre" field of the current record The declarations for the static items in the EditItemTemplate are highlighted Data Reader You can also populate the drop-down list directly from a database. This method is more involved, but it can be more efficient, since you do not actually read the data from the database till the moment you need it. A relatively easy way to do this is to take advantage of Web Forms data-binding expressions. Although it is most common to call the DataBinder.Eval method in a data-binding expression, you can in fact call any public member available to the page. This example shows you how to create a function that creates, fills, and returns a DataTable object that the drop-down list can bind to. For this scenario, you will need to be able to execute a data command that gets the records you want. For example, you might define a data command whose CommandText property is Select * from Genres. To simplify the example, it will be assumed that you have a connection object and a data command object already on the page. Start by creating a public function in the Page That Creates a Dat a table object and defines the columns you need in it. Then open the connection, execute the data command to return a data reader, and loop through the reader, copying the data to the table. Finally, return the table as the function's return value . The following example shows how you can do this. in this case, there is only one column in the returned table ( "genre"). When you populate a drop-down list, you usually need only one column, or two columns if You want to set the drop-down list's text and values to diffreent columns. 'Visual Basic Public Function GetGENRETABLE () AS DataTable Dim DTGENRE AS DATATABLE = New DataTable () IF Application ("GenRetable" ) Is Nothing Then Dim dr As DataRow Dim dc As New DataColumn ( "genre") dtGenre.Columns.Add (dc) Me.SqlConnection1.Open () Dim dreader As SqlClient.SqlDataReader = _ Me.SqlCommand1.ExecuteReader () While dreader .Read () DR = dtgenre.newrow () DR (0) = DREADER (0) dtgenre.Rows.Add (dr) end while me.sqlconnection1.close () else dtgenre = ctype (Application ("genretable), DataTable ) End If Return dtGenre End Function // C # public DataTable GetGenreTable () {DataTable dtGenre = new DataTable (); if (Application [ "GenreTable"] == null) {DataRow dr; DataColumn dc = new DataColumn ( "genre") ; dtGenre.Columns.Add (dc); this.sqlConnection1.Open (); System.Data.SqlClient.SqlDataReader dreader = this.sqlCommand1.ExecuteReader (); while (dreader.Read ()) {dr = dtGenre.NewRow ( DR [0] = DREADER [0]; dtgenre.Rows.Add (DR); } This.sqlConnection1.Close ();} else {dtGenre = (DataTable) Application [ "GenreTable"];} return dtGenre;.} Notice that the function caches the table it creates into Application state Since the table is acting as a static lookup table, you do not need to re-read it every time a different row is put into edit mode. moreover, because the same table can be used by multiple users, you can cache it in the global Application state rather than in user- Specific session state. The Following Shows The Declaration for the Template Column. You will see THAS VERY SIMILAR TO The Syntax Used for Binding to a DataSet Table; the only real difference is that the DataSource binding calls your function. A slight disadvantage of this technique is that you do not get much design-type assistance from Visual Studio. Because you are defining the table to bind to in code, Visual Studio can not offer . you any choices for the DataMember, DataTextField, and DataValueField property settings It is up to you to be sure that you set these properties to the names of the members you create in code s ItemDataBound event. This is the correct event to use, because it guarantees that the drop-down list has already been populated, no matter what data source the drop-down list is using. The trick is in knowing what value to set the drop -down list to. Typically, the value is already available to you either in the current item (being displayed) or in the DataItem property of the current item, which returns a DataRowView object containing the current record. Once you have the value, you can use the DropDownList control's FindByText or FindByValue method to locate the correct item in the list; you can then use the item's IndexOf property to return the index 'Visual Basic Private Sub DataGrid1_ItemDataBound (ByVal sender As Object, _ ByVal e As System.Web. .UI.WebControls.DataGridItemEventArgs) _ Handles DataGrid1.ItemDataBound If e.Item.ItemType = ListItemType.EditItem Then Dim drv As DataRowView = CType (e.Item.DataItem, DataRowView) Dim currentgenre As String = CType (drv ( "genre" ), String) Dim ddl As DropDownList ddl = CType (e.Item.FindControl ( "DropDownList1"), DropDownList) ddl.SelectedIndex = ddl.Items.IndexOf (ddl.Items.FindByText (currentgenre)) End If End Sub // C # private void DataGrid1_ItemDataBound (object sender, System.Web.UI.WebControls.DataGridItemEventArgs e) {if e.Item.DataItem (e.Item.ItemType == ListItemType.EditItem) {DataRowView drv = (DataRowView); String currentgenre = drv [ "genre" ] .Tostring (); DropDownList DDL = (DropdownList) E.Item.FindControl ("DropDownList1"); ddl.selectedIndex = ddl.items.indexof (DDL.Items.FindBytext (currentgenre); }} Selecting Multiple Items Using a Check Box (Hotmail Model) In applications such as Microsoft Hotmail ?, users can "select" rows by checking a box and then performing an operation on all the selected rows - for example, delete them or copy them . to add functionality like this, add a template column to the grid and put a check box into the column. When the page runs, users will be able to check the items they want to work with. to actually perform the user action, you can walk the grid's items collection, looking into the appropriate column (cell) to see if the check box is checked. The following example shows how you can delete rows in a dataset corresponding to the items that a user has checked. The dataset, called dsBooks1, is assumed to contain a table called Books. 'Visual Basic Private Sub btnDelete_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDelete.Click' Walk the grid looking for selected rows Dim i As Integer = 0 DIM CB As Checkbox DIM DGI As DataGridItem Dim bookid As Integer Dim dr As dsBooks.BooksRow For Each dgi In DataGrid1.Items cb = CType (dgi.Cells (0) .Controls (1), CheckBox) If cb.Checked Then 'Determine the key of the selected record ... bookid = ctype (DataGrid1.DataKeys (i), integer) ... get a pointer to the corresponding dataset record ... dr = me.dsbooks1.books.findbybookid (bookid) '... and delete it . dr.Delete () End If i = 1 Next Me.SqlDataAdapter1.Update (DsBooks1) Me.SqlDataAdapter1.Fill (DsBooks1) DataGrid1.DataBind () End Sub // C # private void btnDelete_Click (object sender, System.EventArgs e ) {INT i = 0; checkbox cb; int bookid; dsbooks.booksrow DR; Foreach (DataGridItem DGI In this.DataGrid1.items) {cb = (checkbox) Dgi.cells [0] .controls [1]; if (cb.checked) {// determine the key of the successd record ... bookid = (int) DataGrid1.DataKeys [i]; // ... get a pointer to the corresponding dataset record ... dr = this.dsbooks1.books.findbybookid (bookid); // ... and delete it. DELETE ();} i ;} this.sqldataadapter1.Update (this.dsbooks1); this.sqldataadapter1.fill (this.dsbooks1); dataGrid1.database ();} Some Points to Note: You can determine whether the check box is checked by using the standard approach for getting a control value from a template column -. Getting an object from the Controls collection of the cell and casting it appropriately If you are getting a Checkbox control, remember that it is usually the second control (index 1) because a literal control precedes it (even if it is blank). If you are deleting, you must do so by key and not by offset in the dataset. The index of an item in the DataGrid control might not match the index of the same record in the table. Even if it does at first, after the first record is deleted it will not. Here, the code gets the record key out of the grid's DataKey collection. It then uses the findBy .. Users do not explicitly have to put the grid into edit mode Typically, users make whatever changes they want and then click a button (not a button in the grid) to submit all changes at once The page might look something like the following: figure 1 you can use this style of editing grid with any data model, whether you are working against a dataset or directly against the data source using data commands. To configure the grid for multiple-row edit, add the columns as you normally would and convert all editable columns to template columns. In the Columns tab of the grid's Property Builder, select the column and at the bottom of the window, choose Convert this column into a Template column. to edit the templates, right-click the grid and choose Edit Template. Add the edit controls to the ItemTemplate. Note that you are not adding them to the EditItemTemplate, as you normally would, because the rows will not be displayed in edit mode. that is, the ItemTemplate will contain editable con Trols. set up data binding for the grid Normally. You will NEED TO BIND Each Editable Control Individually. A Typical Data Binding Expression Will Look Like this: DataBinder.eval (Container, "DataItem.title" ) Loading the grid is no different than usual. Updating is slightly different, however, because when users click the Update button, you need to go through the entire grid, making updates for all the rows. The following example shows one possibility. In this case, it is assumed that you are using a data command (dcmdUpdateBooks) that contains a parameterized SQL Update statement. The code walks through the grid, item by item, extracts values from the editable controls, and assigns the values to command parameters. It then executes the data command once for each grid item. 'Visual Basic Private Sub btnUpdate_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnUpdate.Click Dim i As Integer Dim dgi As DataGridItem Dim bookid As Integer Dim TextBoxTitle As TextBox Dim CheckBoxInStock As CheckBox Dim TextBoxPrice As TextBox Dim LabelBookId as Label For i = 0 To DataGrid1.Items.Count - 1 dgi = DataGrid1.Items (i) LabelBookId = CType (dgi.Cells (0) .Controls (1) , Label B ookid = CType (LabelBookId.Text, Integer) TextBoxTitle = CType (dgi.FindControl ( "TextBoxTitle"), TextBox) CheckBoxInStock = _ CType (dgi.FindControl ( "CheckBoxInstock"), CheckBox) TextBoxPrice = CType (dgi.FindControl ( " TextBoxPrice "), TextBox) Me.dcmdUpdateBooks.Parameters (" @ bookid "). Value = bookid Me.dcmdUpdateBooks.Parameters (" @ Title "). Value = TextBoxTitle.Text Me.dcmdUpdateBooks.Parameters (" @ instock "). Value = _ checkboxinstock.checked me.dcmdupdatebooks.parameters ("@ price"). Value = TextBoxPrice.Text Me.SqlConnection1.Open () Me.dcmdUpdateBooks.ExecuteNonQuery () Me.SqlConnection1.Close () Next End Sub // C # private void btnUpdate_Click (object sender, System.EventArgs e) {int i; DataGridItem dgi; int bookid; TextBox TextBoxTitle; CheckBox CheckBoxInStock; TextBox TextBoxPrice; for (i = 0; i <= DataGrid1.Items.Count -1; i ) {dgi = DataGrid1.Items [i]; Label LabelBookId = (Label) dgi.Cells [ 0] .Controls [1]; bookid = int.Parse (LabelBookId.Text); TextBoxTitle = (TextBox) dgi.FindControl ( "TextBoxTitle"); CheckBoxInStock = (CheckBox) dgi.FindControl ( "CheckBoxInStock"); TextBoxPrice = ( TextBox) dgi.FindControl ( "TextBoxPrice");. this.dcmdUpdateBooks.Parameters [ "@ bookid"] Value = bookid; this.dcmdUpdateBooks.Parameters [ "@ Title"] Value = TextBoxTitle.Text;. this.dcmdUpdateBooks.Parameters [ "@instock"] Value = CheckBoxInStock.Checked;.. this.dcmdUpdateBooks.Parameters [ "@ Price"] Value = float.Parse (TextBoxPrice.Text); this.sqlConnection1.Open (); this.dcmdUpdateBooks.ExecuteNonQuery ( ) this.sqlConnection1.close (); }} Checking for Changed Items One disadvantage of the update strategy illustrated above is that it can be inefficient to send updates to the dataset or database for each grid row if there have been only a few changes. If you are working with a dataset, you . can add logic to check for changes between the controls in the grid and the corresponding columns in dataset rows If you are not using a dataset - as in the example above - you can not easily make this comparison, since it would involve a round trip to the database. A strategy that works for both types of data sources is to establish a way to determine whether rows are "dirty" so you can check that before making an update. The definitive way to determine whether a row has been dirtied is to handle the changed event for the controls in a row. for example, if your grid row contains a TextBox control, you can respond to the control's TextChanged event. Similarly, for check boxes, you can respond to a CheckedChanged event. in the handle r for these events, you maintain a list of the rows to be updated. Generally, the best strategy is to track the primary keys of the affected rows. For example, you can maintain an ArrayList object that contains the primary keys of the rows to . update Imagine that you want to follow this strategy for the example above Create an instance of an ArrayList object as a member of the page class:. 'Visual Basic protected bookidlist As ArrayList = New ArrayList () // C # protected ArrayList bookidlist = new Arraylist (); Then create a handler to add the book ID to the ArrayList object whenever a control is changed The following code shows a handler that can be invoked when a TextBox control raises its TextChanged event or when a CheckBox control raises its CheckedChanged event:. 'Visual Basic Protected Sub RowChanged (ByVal sender As Object, _ ByVal e As System.EventArgs) Dim dgi As DataGridItem = _ CType (CType (sender, Control) .NamingContainer, DataGridItem) Dim bookidlabel As Label = CType (dgi.Cells (0). Controls (1), Label) Dim bookid As Integer = CType (bookidlabel.Text, Integer) If Not (bookidlist.Contains (bookid)) Then bookidlist.Add (bookid) End If End Sub // C # protected void RowChanged (object sender , System.EventArgs e) {DataGridItem dgi = (DataGridItem) (((Control) sender) .NamingContainer); Label bookidlabel = (Label) dgi.Cells [0] .Controls [1]; int bookid = int.Parse (bookidlabel .Text); if (! Bookidlist.contains) {BookidList.add (Bookid);}} Note The Method Cannot Be Private, or You Will NOT Be able to bind to it lat. It is helpful to understand that change events do not, by default, post the page back to the server. Instead, the event is raised only when the page is posted some other way (usually via a Click event). During page processing, the page and its controls are initialized, and then all change events are raised. Only when the change event's handlers have finished is the Click event raised for the control that caused the post. On to the RowChanged method illustrated above. The code needs to get the book ID out of the current item. The event does not pass the item to you (as it does for many DataGrid events, for example), so you have to work backwards. From the sender argument of the event, get the NamingContainer property, which will be the grid item. From there, you can drill back down to get the value of the Label control that displays the book ID. you need to check that the book ID is not already in the array. Each control in the row raises The Event Individally, SO if There Has Been AC hange in more than one control, you could potentially end up adding the book ID to the array more than once. The change events for controls are always raised and handled before click events. Therefore, you can build the array list in the change event and know that it will be available when the event handler runs for the button click that posted the form (in this example, the btnUpdate_Click handler). Now that you have the array list, you can make a minor modification to the handler that manages the update ......................... .. Visual Basic Private Sub btnUpdate_Click (ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnUpdate.Click Dim i As Integer Dim dgi As DataGridItem 'Rest of declarations here For i = 0 To DataGrid1.Items.Count - 1 dgi = DataGrid1.Items (i) LabelBookId = CType (dgi.Cells (0) .Controls (1), Label) If bookidlist.Contains (bookid) Then TextBoxTitle = CType (dgi.FindControl ( "TextBoxTitle"), TextBox) ' REST OF Update Code Here End End End Sub // C # Private Void BtnUpdate_Click (Object Sender, System.EventArgs E) {INT I; DataGridItem DGI; INT BookId; // REST OF Declarations Here for (i = 0; i <= DataGrid1.Items.count -1; i ) {DGI = DataGrid1.items [i]; TableCell Tc = DGI.Cells [0]; string s = dgi.cells [0] .Text; label labelbookid = (label) DGI. Cells [0] .controls [1]; bookid = int.parse (LabelBookid.Text); if (BookidList.Contains (Bookid)) {// Update code Here}}} One task is left: binding the handlers to the control Events. In Visual Studio, You Can Only Do this in HTML V . Iew The controls are not explicitly instantiated in the code-behind file, so they are not supported by the code tools Switch the .aspx file to HTML view and in the declarative elements for each of the controls, add the following highlighted syntax.: asp: checkbox id = cbinstock oncheckedchanged = "rowchanged" runat = "server" checked = '<% # databinder.eval (container, "dataitem.instock")%>> asp: checkbox> itemtemplate> asp: TemplateColumn> both the TextBox and CheckBox controls can call the same method from their respective change methods, because the signature for both event handlers is the same That would be true also if you had a list box or drop-down list control,. whose SelectedIndexChanged events likewise pass the same arguments. Selecting rows by Clicking Anywhere The default model for selecting rows in the grid is for you to add a Select button (actually, a LinkButton control) whose CommandName property is set to "Select." When the button is clicked, the DataGrid control receives the Select command and automatically displays the row in selected mode. Not everyone likes having an explicit Select button, and a common question is how to implement the feature where users can click anywhere in a grid row to select It. The solution is to perform a kind of sleight-of-hand in the grid. You add the Select LinkButton control as normal. Users can still use it, or you can hide it. In either event, you then inject some client script into the page that Effectively duplicates the functionality of the select button for the row as a whole. The example below shows how. in the grid ' s ItemDataBound handler, first make sure that you are not in the header, footer, or pager. Then get a reference to the Select button, which in this instance is assumed to be the first control in the first cell. You then call a little -known method called GetPostBackClientHyperlink. This method returns the name of the postback call for the designated control. in other words, if you pass in a reference to a LinkButton control, it returns the name of the client function call that will perform the postback. Finally, you assign the client-side method to the item itself. When the grid renders, it renders as an HTML table. By assigning the method to the item, it is the equivalent of adding client-side code to each row ( element) in the table. The grid's Item object does not directly support a way to assign client code to it, but you can do that by using its Attributes collection, which passes anything you assign to it through to the browser.Note One small Disadvantage of this Technique I S That IT Added To The Browser, And It Adds Information for Each Row To View State.