using system;
using system.web.ui.webcontrols;
using system.data;
/*
* the control assumes the following:
*
* 1) it is bound to a dataview object.
* 2) the app will use direct sql commands to update the source (no batch update).
* 3) no custom paging is enabled.
*
* if you plan to support sorting, then some aspects of this code should be reviewed
* and adapted.
*
*/
namespace bwslib
{
namespace controls
{
public class editablegrid : datagrid
{
// constructor that sets some styles and graphical properties
public editablegrid()
{
allowfullediting = true;
addnewrow = false;
rejectchanges = false;
mustinsertrow = false;
allowpaging = true;
// handlers
init += new eventhandler(oninit);
pageindexchanged += new datagridpagechangedeventhandler(onpageindexchanged);
itemcreated += new datagriditemeventhandler(onitemcreated);
cancelcommand += new datagridcommandeventhandler(oncancelcommand);
editcommand += new datagridcommandeventhandler(oneditcommand);
updatecommand += new datagridcommandeventhandler(onupdatecommand);
deletecommand += new datagridcommandeventhandler(ondeletecommand);
}
// property: allowfullediting
// enable full editing
public bool allowfullediting;
// property: addnewrow
// if true must add an empty row at the bottom of the data source
public bool addnewrow;
// internal property: rejectchanges
// if true must reject changes on the last row of the data source
protected bool rejectchanges;
// internal property: mustinsertrow
// if true must insert instead of update and theres a pending change
protected bool mustinsertrow
{
get {return convert.toboolean(viewstate["mustinsertrow"]);}
set {viewstate["mustinsertrow"] = value;}
}
// property: datasource (override)
public override object datasource
{
get {return base.datasource;}
set
{
base.datasource = value;
if (allowfullediting)
{
if (addnewrow)
{
addnewrow = false;
insertnewrow();
}
if (allowfullediting && rejectchanges)
{
rejectchanges = false;
mustinsertrow = false;
rejectchangesonlastrow();
}
}
}
}
// property: command columns
public bool showwebdings = false;
public string editcolumntext = "edit";
public string editcolumnupdatetext = "ok";
public string editcolumncanceltext = "cancel";
public string deletecolumntext = "delete";
// event: initrow
public delegate void datagridinitroweventhandler(object sender, datagridinitroweventargs e);
public event datagridinitroweventhandler initrow;
private void oninitrow(datagridinitroweventargs e)
{
if (initrow != null)
initrow(this, e);
}
// event: updateview
public event eventhandler updateview;
protected virtual void onupdateview(eventargs e)
{
if (updateview != null)
updateview(this, e);
}
// event: savedata
public event datagridcommandeventhandler savedata;
protected virtual void onsavedata(datagridcommandeventargs e)
{
if (savedata != null)
savedata(this, e);
}
// event: insertdata
public event datagridcommandeventhandler insertdata;
protected virtual void oninsertdata(datagridcommandeventargs e)
{
if (insertdata != null)
insertdata(this, e);
}
// event: deletedata
public event datagridcommandeventhandler deletedata;
protected virtual void ondeletedata(datagridcommandeventargs e)
{
if (deletedata != null)
deletedata(this, e);
}
// event handler: init
public void oninit(object sender, eventargs e)
{
if (allowfullediting)
addworkercolumns();
}
// event handler: itemcreated
public void onitemcreated(object sender, datagriditemeventargs e)
{
listitemtype lit = e.item.itemtype;
if (lit == listitemtype.item || lit == listitemtype.alternatingitem)
customizeitem(e);
}
// event handler: cancelcommand
public void oncancelcommand(object sender, datagridcommandeventargs e)
{
if (e.item.itemindex == 0)
currentpageindex = (currentpageindex==0 ?0 :currentpageindex-1);
// clears edit mode
edititemindex = -1;
// reject changes on the last row
rejectchanges = true;
// show/hide delete column
toggledeletecolumn(true);
// refresh view
onupdateview(eventargs.empty);
}
// event handler: editcommand
public void oneditcommand(object sender, datagridcommandeventargs e)
{
// reject changes on the last row (if any)
rejectchanges = true;
// show/hide delete column
toggledeletecolumn(false);
// enable editing on the clicked row
edititemindex = e.item.itemindex;
// refresh view
onupdateview(eventargs.empty);
}
// event handler: updatecommand
public void onupdatecommand(object sender, datagridcommandeventargs e)
{
// clear edit mode
edititemindex = -1;
// show/hide delete column
toggledeletecolumn(true);
// reject changes on the last row
rejectchanges = true;
// update or insert data
if (mustinsertrow)
oninsertdata(e);
else
onsavedata(e);
// refresh view
onupdateview(eventargs.empty);
}
// event handler: deletecommand
public void ondeletecommand(object sender, datagridcommandeventargs e)
{
// clear edit mode
edititemindex = -1;
// delete data
ondeletedata(e);
// first item in the row, one page back
if (items.count == 1)
currentpageindex = (currentpageindex==0 ?0 :currentpageindex-1);
// refresh view
onupdateview(eventargs.empty);
}
// event handler: pageindexchanged
public void onpageindexchanged(object sender, datagridpagechangedeventargs e)
{
// clears edit mode
edititemindex = -1;
// reject changes on the last row
rejectchanges = true;
// show/hide delete column
toggledeletecolumn(true);
// set the new page index
currentpageindex = e.newpageindex;
// refresh data
onupdateview(eventargs.empty);
}
/* ———————————————————————*/
/* ———————— internals ———————————*/
/* ———————————————————————*/
// reject changes on the last row
private void rejectchangesonlastrow()
{
// get the underlying datatable object
datatable dt = ((dataview) datasource).table;
datarow drlast = dt.rows[dt.rows.count-1];
if (drlast.rowstate == datarowstate.added)
drlast.rejectchanges();
}
// show/hide the delete column when in edit mode
private void toggledeletecolumn(bool bviewstate)
{
int ngridcolcount = columns.count;
columns[ngridcolcount-1].visible = bviewstate;
}
// put the grid in edit mode by adding a blank row
private void insertnewrow()
{
// show/hide delete column
toggledeletecolumn(false);
// get the underlying datatable object
datatable dt = ((dataview) datasource).table;
// if any pending changes, stop here…
datatable tmptableofpendingchanges = dt.getchanges(datarowstate.added);
if (tmptableofpendingchanges != null)
return;
// add the new row
datarow row = dt.newrow();
dt.rows.add(row);
// initialize the row
datagridinitroweventargs dgire = new datagridinitroweventargs();
dgire.row = row;
oninitrow(dgire);
// goto to last page (return last index in the page)
int nnewitemindex = setindexestolastpage(dt);
// turn edit mode on for the newly added row
edititemindex = nnewitemindex;
// tracks that a new row has just been added
mustinsertrow = true;
}
// update indexes to point to last page
private int setindexestolastpage(datatable dt)
{
int nremainder = (dt.rows.count % pagesize);
int nnewitemindex = nremainder;
currentpageindex = (dt.rows.count / pagesize)-1; // 0-based
if (currentpageindex <0)
currentpageindex = 0;
if (nnewitemindex >0)
currentpageindex ++;
if (nnewitemindex == 0)
nnewitemindex = pagesize-1;
else
nnewitemindex–;
return nnewitemindex;
}
// add edit and delete columns
private void addworkercolumns()
{
if (showwebdings)
{
editcolumntext = "/";
editcolumnupdatetext = "r";
editcolumncanceltext = "t";
deletecolumntext = "r";
}
// edit column
editcommandcolumn editcolumn = new editcommandcolumn();
editcolumn.edittext = editcolumntext;
editcolumn.updatetext = editcolumnupdatetext;
editcolumn.canceltext = editcolumncanceltext;
if (showwebdings)
{
editcolumn.itemstyle.font.size = 11;
editcolumn.itemstyle.font.name = "wingdings 2";
}
columns.add(editcolumn);
// delete column
buttoncolumn deletecolumn = new buttoncolumn();
deletecolumn.commandname = "delete";
deletecolumn.text = deletecolumntext;
if (showwebdings)
deletecolumn.itemstyle.font.name = "webdings";
columns.add(deletecolumn);
}
// customize items in the grid
private void customizeitem(datagriditemeventargs e)
{
webcontrol wc;
// adds a tooltip to edit
wc = ((webcontrol) e.item.cells[columns.count-2]);
wc.tooltip = "edit this row";
// adds a client-side onclick handler and a tooltip to delete
wc = ((webcontrol) e.item.cells[columns.count-1]);
string js = "return confirm(do you really want to delete this row?);";
wc.attributes["onclick"] = js;
wc.tooltip = "delete this row";
}
}
public sealed class datagridinitroweventargs : eventargs
{
public datarow row;
}
}
}
