Fully Editable Datagrid

This is the text from an article I wrote back in April of 2003 and had published on the original DotNetJunkies site. After my recent change in my web address I realized that the old adage about never removing a link stands true today. Apparently people are still getting to my article from The DataGrid Girl, Expert Exchange and other sites so I’ve reproduced it here. Unfortunately, I have not figured out how to make the original URL go here, but I’ll work on that. Update: I did a search and found out how amazingly simply it is within apache to redirect pages. I had a suspicion this would be the case, just not the time to confirm. Now it’s done!

Update: I’ve been receiving requests for the source code to the article. Apparently it is no longer available on DotNetJunkies. I’ve made available for download both the VB source and the C# source.

Update: The sources that were originally linking to this post have now disappeared.  Now traffic is coming from search engines.

I have seen many questions in the forums that ask the same or a very similar question. How do I put a check box, text box, etc.. in every row of my DataGrid and then update the values? The answer is rather simple and in this article I will show you how this is accomplished.

We all know that the DataGrid can be a very powerful tool. Most of the time, 90%+ in my
experience, the DataGrid is used to display data and possibly edit one row of data at a time.
There are circumstances that arise that may call for the need to edit multiple, even all, rows at one time. A good example of this is in a shopping cart application where the customer can update the quantity of one or more items in their basket at once and click check boxes to remove unwanted products.

The Scenario

In this example I have written a simple WebForm to manage a list of contacts which I have stored in XML. The requirements are simply the ability to add new contacts and to be able to modify or delete existing contacts. The user should be able to modify or delete multiple contacts at one time. I have also allowed the user to sort their grid by the column of their choosing.

My example is written in C#. If you prefer the VB version of this code, both version
are available in the download.

Contacts.xml

The XML data file for this example is fairly simple and straight forward. Due to the simplicity, I have not created a schema.

<?xml
version=”1.0″ standalone=”yes”?>

<Contacts>

<Contact>

<Email>myaddress@mycompany.com</Email>

<FirstName>John</FirstName>

<LastName>Doe</LastName>

</Contact>

<Contact>

<Email>youraddress@yourcompany.com</Email>

<FirstName>Jane</FirstName>

<LastName>Doe</LastName>

</Contact>

</Contacts>

ContactList.aspx

Setting up the
WebForm is simple as well. I placed a new
DataGrid
onto my form and gave it four columns, one for each field plus one to contain
the
CheckBox
for deleting a contact. You will notice that the main thing I did here is
created each column as a TemplateColumn. This allowed me to put the
TextBox
and
CheckBox
objects into the
ItemTemplate.
This is the trick to displaying something other than text in each row of the
grid. In addition you’ll notice that I’ve used the
FooterTemplate
to make the addition of new contacts easy and (hopefully!) intuitive.

I’ve also included a
single
LinkButton
which is used to save user modifications and deletions. It is not,
however, used to add new contacts. That is done by the link button in the
FooterTemplate
of the last column.

<asp:datagrid
id=”dgContacts” runat=”server” ShowFooter=”True” AllowSorting=”True” Forefont
color=”Black” GridLines=”None” CellPadding=”2″ Backfont
color=”LightGoldenrodYellow” BorderWidth=”1px” Borderfont color=”Tan”
Width=”499px” AutoGenerateColumns=”False” DataKeyField=”Email”>

<SelectedItemStyle Forefont color=”GhostWhite” Backfont
color=”DarkSlateBlue”></SelectedItemStyle>

<AlternatingItemStyle Backfont
color=”PaleGoldenrod”></AlternatingItemStyle>

<HeaderStyle Font-Bold=”True” Backfont
color=”Tan”></HeaderStyle>

<FooterStyle Backfont color=”Tan”></FooterStyle>

<Columns>

<asp:TemplateColumn SortExpression=”FirstName”
HeaderText=”First Name”>

<ItemTemplate>

<asp:TextBox id=First
runat=”server” Width=”109px” Text='<%# DataBinder.Eval(Container,
“DataItem.FirstName”) %>’>

</asp:TextBox>

</ItemTemplate>

<FooterTemplate>

<asp:TextBox id=”NewFirst”
runat=”server” Width=”109px”></asp:TextBox>

</FooterTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn SortExpression=”LastName”
HeaderText=”Last Name”>

<ItemTemplate>

<asp:TextBox id=Last
runat=”server” Width=”109px” Text='<%# DataBinder.Eval(Container,
“DataItem.LastName”) %>’>

</asp:TextBox>

</ItemTemplate>

<FooterTemplate>

<asp:TextBox id=”NewLast”
runat=”server” Width=”109px”></asp:TextBox>

</FooterTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn SortExpression=”Email”
HeaderText=”Email”>

<ItemTemplate>

<asp:TextBox id=Email
runat=”server” Text='<%# DataBinder.Eval(Container, “DataItem.Email”)
%>’>

</asp:TextBox>

</ItemTemplate>

<FooterTemplate>

<asp:TextBox id=”NewEmail”
runat=”server”></asp:TextBox>

</FooterTemplate>

</asp:TemplateColumn>

<asp:TemplateColumn HeaderText=”Delete Contact”>

<ItemStyle
HorizontalAlign=”Center”></ItemStyle>

<ItemTemplate>

<asp:CheckBox Runat=”server”
ID=”chkDelete”></asp:CheckBox>

</ItemTemplate>

<FooterStyle
HorizontalAlign=”Center”></FooterStyle>

<FooterTemplate>

<asp:LinkButton Runat=”server”
Text=”Add” CommandName=”Add” ID=”Linkbutton1″
NAME=”Linkbutton1″></asp:LinkButton>

</FooterTemplate>

</asp:TemplateColumn>

</Columns>

</asp:datagrid>

 

ContactList.cs

Since I elected to
store my data in an XML file, I have decided to use a
DataSet
for accessing it. Since the
DataSet
object has the
ReadXml
and
WriteXml
methods it was a fairly logical choice. My first step was to read in
the XML. As you can see from the code, I also added a the foundation to
handle sorting.

private
DataSet _dsContacts;

private string _sSort;

private void Page_Load(object
sender, System.EventArgs e)

{

// Load the XML file.

_dsContacts = new DataSet();

_dsContacts.ReadXml(Server.MapPath(“Contacts.xml”));

DataColumn[] dcPk = {_dsContacts.Tables[“Contact”].Columns[“Email”]};

_dsContacts.Tables[“Contact”].PrimaryKey =
dcPk;

if (!Page.IsPostBack )

{

// Only bind at this point if this is
the first page request.

BindContacts();

_sSort = “FirstName”;

}

else

{

// Read the sort order from the view
state.

_sSort = (string)ViewState[“Sort”];

}

}

Next I created the
method used to bind the data to the grid, which includes the logic for sorting
the data and a method to persist the XML back to the disk.

privatevoid BindContacts()
{
// Save the sort order to the view state.

ViewState[“Sort”] = _sSort;

// Bind the grid to the sorted data view.
DataView dv =
new
DataView(_dsContacts.Tables[“Contact”]);
dv.Sort = _sSort;
dgContacts.DataSource = dv;
dgContacts.DataBind();
}

private
void SaveContacts()
{

_dsContacts.WriteXml(Server.MapPath(“Contacts.xml”));
}

The
ItemCommand
event is where new contacts are added to the list. Note that I checked
the
CommandName
argument for a value of Add. This is the value that was
set back in the ASPX page for the LinkButton
in the
FooterTemplate
of the last column in the grid.

privatevoid
dgContacts_ItemCommand(object source ,
System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
// Add the new item to the dataset. I use an
array here for efficiency.
if (e.CommandName ==
“Add”)
{

string[] sContact =
{“”, “”, “”};
sContact[0] =
((TextBox)e.Item.FindControl(“NewEmail”)).Text;
sContact[1] =
((TextBox)e.Item.FindControl(“NewFirst”)).Text;
sContact[2] = ((TextBox)e.Item.FindControl(“NewLast”)).Text;

_dsContacts.Tables[“Contact”].Rows.Add(sContact);

SaveContacts();
}

BindContacts();
}

I will skip the
SortCommand
code since there are a lot of other articles out there that deal with sorting
in much more detail. If you download the code for this example it is
included.

Finally I moved on to the
OnClick
event of the
LinkButton
on the form. This is where I looped through the items in the
DataGrid
to perform any necessary deletes and updates.

privatevoid btnUpdate_Click(object sender,
System.EventArgs e)
{
// Loop through the items in the
datagrid.

foreach (DataGridItem di in
dgContacts.Items)
{
// Make sure this is an item and not the header or
footer.

if (di.ItemType ==
ListItemType.Item || di.ItemType ==
ListItemType.AlternatingItem)

{
// Get the current row for update or delete operations
later.

DataRow dr = _dsContacts.Tables[“Contact”].Rows.Find(dgContacts.DataKeys[di.ItemIndex]);

// See if this one needs to be deleted.

if (((CheckBox)di.FindControl(“chkDelete”)).Checked)

{
_dsContacts.Tables[“Contact”].Rows.Remove(dr);

}
else

{
// Update the row instead.

dr[“Email”] = ((TextBox)di.FindControl(“Email”)).Text;
dr[“FirstName”] = ((TextBox)di.FindControl(“First”)).Text;
dr[“LastName”] = ((TextBox)di.FindControl(“Last”)).Text;

}
}
}

// Save the changes if there are any.

if
(_dsContacts.HasChanges())

{
SaveContacts();
}

BindContacts();
}

Conclusion

I could have just as
easily referenced the controls by their positions within the the Cells(x) of
each DataGridItem. The point is, there’s more than one way to skin a cat
and I’m sure that you can find some better ways to accomplish this
task. As you can see it’s quite easy to edit entire data grids at
one time. This same approach will also work with paged grids with a
little modification.
Copyright 2002 Palehorse.NET

4 thoughts on “Fully Editable Datagrid

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s