Code for the bulk edit grid view
Nicolas Galler | December 24, 2007In follow up to my post on the bulk edit grid view, here is the code I used for the grid view. It should be noted that most of the code and the inspiration were directly lifted from this post.
The code is in 2 parts:
- MixableGridView, this is a very small addition to the grid view to add an event. I like using this and add my extensions to the grid view rather than inheriting every time from GridView since it makes it more modular.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using log4net; namespace SSSWorld.WebControls { /// <summary> /// Simple customization to the stock grid view to enable a few extra events. /// This is used by the Mixin controls. /// </summary> [ToolboxData("<{0}:MixableGridView runat=server></{0}:MixableGridView>")] public class MixableGridView : GridView { private static readonly ILog LOG = LogManager.GetLogger(typeof(MixableGridView)); private static readonly object EventRowInitializing = new object(); /// <summary> /// Raised right before the row is created. /// Last place changes can be made to the row before its child controls are /// instantiated. /// </summary> public event GridViewRowEventHandler RowInitializing { add { base.Events.AddHandler(EventRowInitializing, value); } remove { base.Events.RemoveHandler(EventRowInitializing, value); } } protected override void InitializeRow(GridViewRow row, DataControlField[] fields) { GridViewRowEventHandler handler = (GridViewRowEventHandler)base.Events[EventRowInitializing]; if (handler != null) handler(this, new GridViewRowEventArgs(row)); base.InitializeRow(row, fields); } } }
- BulkEditGridViewMixin is the actual extension that enables the bulk-editing.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using log4net; namespace SSSWorld.WebControls { /// <summary> /// Mixin allowing edit of all rows within a gridview at the same time. /// Note that this will be sub-optimal with a "connected" data source /// (eg a SqlDataSource) - should be used with EntityDataSource for best /// results. /// </summary> public class BulkEditGridViewMixin : UserControl { private static readonly ILog LOG = LogManager.GetLogger(typeof(BulkEditGridViewMixin)); private bool _inDataBinding = false; private bool _saved = false; /// <summary> /// Id of the grid for which to enable the bulk edit. /// Must be a MixableGridView instance. /// </summary> public String GridId { get { return ViewState["GridId"] as String; } set { ViewState["GridId"] = value; } } private MixableGridView Grid { get { MixableGridView grid = NamingContainer.FindControl(GridId) as MixableGridView; if (grid == null) { throw new ArgumentException("Invalid GridId parameter - must point to a MixableGridView"); } return grid; } } /// <summary> /// Initialize the event handlers for the grid. /// </summary> /// <param name="e"></param> protected override void OnInit(EventArgs e) { base.OnInit(e); Grid.RowInitializing += new GridViewRowEventHandler(Grid_RowInitializing); Grid.RowUpdated += new GridViewUpdatedEventHandler(Grid_RowUpdated); Grid.DataBinding += new EventHandler(Grid_DataBinding); Grid.PageIndexChanging += new GridViewPageEventHandler(Grid_PageIndexChanging); } /// <summary> /// Ensure we save the edits right before changing the page. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void Grid_PageIndexChanging(object sender, GridViewPageEventArgs e) { if(!e.Cancel) SaveGrid(); } /// <summary> /// Save the grid's data before refreshing it. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Grid_DataBinding(object sender, EventArgs e) { if (!_inDataBinding) { _inDataBinding = true; SaveGrid(); _inDataBinding = false; } } /// <summary> /// Ensure we keep the rows in edit mode. /// This also prevents the DataBinding event from re-firing inside /// of SaveGrid. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void Grid_RowUpdated(object sender, GridViewUpdatedEventArgs e) { e.KeepInEditMode = true; } /// <summary> /// Force rows to edit mode. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Grid_RowInitializing(object sender, GridViewRowEventArgs e) { if(e.Row.RowType == DataControlRowType.DataRow) e.Row.RowState |= DataControlRowState.Edit; } /// <summary> /// Commit grid data to the data source. /// This is automatically when the grid refreshes its data to ensure the /// edits are not lost eg when paging. But it may also have to be called /// explicitely eg when the form's data needs to be committed to the database. /// eg when paging. /// </summary> public void SaveGrid() { if (_saved || Grid.Rows.Count == 0) return; try { LOG.Debug("Updating grid data: " + Grid.Rows.Count); for (int i = 0; i < Grid.Rows.Count; i++) { if (Grid.Rows[i].RowType == DataControlRowType.DataRow) { Grid.UpdateRow(i, false); } } _saved = true; } catch (Exception x) { LOG.Warn("Error in SaveGrid", x); throw; } } } }
Finally, here is how you would use it in an aspx page:
<sss:MixableGridView runat="server" DataSourceID="dsReturnProducts" ID="grdReturnProducts" GridLines="None"
AutoGenerateColumns="false" CellPadding="4" CssClass="datagrid" PagerStyle-CssClass="gridPager"
AlternatingRowStyle-CssClass="rowdk" RowStyle-CssClass="rowlt" SelectedRowStyle-CssClass="rowSelected"
AllowPaging="True" PageSize="10"
EnableViewState="false" DataKeyNames="_AccountProductId" >
<EmptyDataTemplate>
(no product selected)
</EmptyDataTemplate>
<Columns>
<asp:BoundField DataField="ProductName" ReadOnly="true" HeaderText="Product Name" />
<asp:BoundField DataField="SKU" ReadOnly="true" HeaderText="SKU" />
<asp:BoundField DataField="AssetCode" ReadOnly="true" HeaderText="Date Code" />
<asp:BoundField DataField="NoOfBoxes" HeaderText="No. Boxes" />
<asp:BoundField DataField="TotalWeight" HeaderText="Total Weight" />
</Columns>
</sss:MixableGridView>
<sss:BulkEditGridViewMixin ID="grdReturnProductsEdit" GridId="grdReturnProducts" runat="server" />
<sss:SlxEntityDataSource EntityDataSourceProperty="ReceivedProducts" ID="dsReturnProducts"
runat="server"/>
There isn’t much to do in the code behind, but you may have to manually call the SaveGrid() method sometimes (depending on when you need the data to be available vs when you databind the grid). I just call it before doing my final Save on the form.
You can use any datasource control instead of the SlxEntityDataSource. But remember that if the datasource is “connected” (I mean, if its Update method actually sends an update command to the database, regardless of whether there is any change from the original or not) the performance may be pretty bad.





