How to Uncheck Select All Checkbox when one checkbox is Unchecked - c#

I have a checkbox named Select All. When I click this then all other check box inside my Gridview is Checked. But I want when anyone of the checkbox inside the grid will be unchecked then this Select All Checkbox will automatically uncheck. Is there anyone who can help me on this Please?
Thank you.

function SelectheaderCheckboxes(headerchk) {
debugger
var gvcheck = document.getElementById('gvdetails');
var i;
//Condition to check header checkbox selected or not if that is true checked all checkboxes
if (headerchk.checked) {
for (i = 0; i < gvcheck.rows.length; i++) {
var inputs = gvcheck.rows[i].getElementsByTagName('input');
inputs[0].checked = true;
}
}
//if condition fails uncheck all checkboxes in gridview
else {
for (i = 0; i < gvcheck.rows.length; i++) {
var inputs = gvcheck.rows[i].getElementsByTagName('input');
inputs[0].checked = false;
}
}
}
<asp:GridView ID="gvdetails" runat="server" DataSourceID="dsdetails" onrowdatabound="gvdetails_RowDataBound" >
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="chkheader" runat="server" onclick="javascript:SelectheaderCheckboxes(this)" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkchild" runat="server"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

You can do this on the client or the server side
Client side using javascript/jquery
As the checkboxes are added dynamically you will need to use the on method to bind the checkboxes to the function and fire it when their state changes.
$(document).ready(function() {
$(".checkbox").on("change", function() {
if(!$(this).is(":checked")){
$(".selectAll").prop('checked', false);
}
});
});
Here is a jsFiddle with a full functioning select All that will:
Select All / Deselect All
Untick Select All when one of the checkboxes is unticked
Tick select All when all checkboxes are ticked
Server side
use an event handler to on a postback(ajax) when a checkbox is unticked and loop through all checkboxes and untick them
Font-end uses ajax to do a partial postback to update the gridview.
the select all checkbox and gridview checkboxes will trigger the postback.
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:GridView ID="gvCheckBoxes" runat="server">
<Columns>
<asp:TemplateField >
<ItemTemplate>
<asp:CheckBox ID="cbCheckBox" OnCheckedChanged="CheckBoxChanged" AutoPostBack="true" runat="server" />
</ItemTemplate>
/asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="cbSelectAll"/>
</Triggers>
</asp:UpdatePanel>
Code Behind
The select All check box event handler loops through the gridview and finds the checkboxes.
It ticks them if the select all checkbox is ticked otherwise it unticks them
The gridview checkbox event handler loops through the checkboxes and sets a flag to determine if it should tick or untick the select all checkbox. It exists the loop if any of the checkboxes are not ticked as select all must therefore be unticked as well
public void SelectAll (Object sender, Eventargs e)
{
foreach (var row in grid.Rows)
{
var checkBox = (CheckBox)row.FindControl("cbCheckBox");
checkBox.Checked = cbSelectAll.Checked;
}
}
public void CheckBoxChanged(Object sender, Eventargs e)
{
var isSelectAll = true;
foreach (var row in grid.Rows)
{
var checkBox = (CheckBox)row.FindControl("cbCheckBox");
if(!checkBox.Checked)
{
isSelectAll = false;
break;
}
}
cbSelectAll.Checked = isSelectAll;
}

Best way I can think of is to convert the GridView's CheckBoxField to a TemplateField. Then wire up the new asp:CheckBox in your TemplateField to the CheckedChanged event. In your code-behind, you handle the CheckedChanged event, then when any of the checkboxes change to unchecked, you can toggle your "check all" checkbox.

Look at this code. hope this will help you
<div>
<asp:CheckBox ID="chkSelectAll" runat="server" />
<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="chkSelect" runat="server" oncheckedchanged="chkSelect_CheckedChanged" AutoPostBack="true" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
protected void chkSelect_CheckedChanged(object sender, EventArgs e)
{
bool isFound = false;
foreach (GridViewRow gvr in GridView1.Rows)
{
CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;
if (chkSelect.Checked == false)
{
isFound = true;
break;
}
}
if (isFound)
{
chkSelectAll.Checked = false;
}
else
{
chkSelectAll.Checked = true;
}
}

The following code should work. I tested it.
Javascript:
<script type="text/javascript">
function OnOneCheckboxSelected(chkB) {
var IsChecked = chkB.checked;
var Parent = document.getElementById('gridFileList');
var cbxAll;
var items = Parent.getElementsByTagName('input');
var bAllChecked = true;
for (i = 0; i < items.length; i++) {
if(items[i].id.indexOf('cbxSelectAll') != -1){
cbxAll = items[i];
continue;
}
if (items[i].type == "checkbox" && items[i].checked == false) {
bAllChecked = false;
break;
}
}
cbxAll.checked = bAllChecked;
}
function SelectAllCheckboxes(spanChk) {
var IsChecked = spanChk.checked;
var cbxAll = spanChk;
var Parent = document.getElementById('gridFileList');
var items = Parent.getElementsByTagName('input');
for (i = 0; i < items.length; i++) {
if (items[i].id != cbxAll.id && items[i].type == "checkbox") {
items[i].checked = IsChecked;
}
}
}
</script>
ASPX Markup:
<asp:TemplateField HeaderText="Select">
<HeaderTemplate>
<asp:CheckBox ID="cbxSelectAll" OnClick="javascript:SelectAllCheckboxes(this);" runat="server" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox OnClick="javascript:OnOneCheckboxSelected(this);" ID="cbxSelect" runat="server" />
</ItemTemplate>
</asp:TemplateField>

Above code I modifiyed it, if user unchecked the child rows of grid. grid header will automatically uncheck.
<script type="text/javascript">
function UncheckHeader(headerchk) {
var gvcheck = document.getElementById('gvdetails');
var inputs = gvcheck.rows[0].getElementsByTagName('input');
inputs[0].checked = false;
}
function SelectAll(headerchk) {
var gvcheck = document.getElementById('gvdetails');
var i;
// if true checked all checkboxes
if (headerchk.checked) {
for (i = 0; i < gvcheck.rows.length; i++) {
var inputs = gvcheck.rows[i].getElementsByTagName('input');
inputs[0].checked = true;
}
}
//if condition fails uncheck all checkboxes in gridview
else {
for (i = 0; i < gvcheck.rows.length; i++) {
var inputs = gvcheck.rows[i].getElementsByTagName('input');
inputs[0].checked = false;
}
}
}
</script>
<asp:GridView ID="gvdetails" runat="server" >
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="chkheader" runat="server" onclick="javascript:SelectAll(this)" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkchild" runat="server" onclick="javascript:UncheckHeader(this)" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
more details here

Related

Adding a checkbox column to asp.net gridview

I have a couple questions when it pertains to adding a CheckBox column to gridview in asp.net and getting multiple values. First off I see everyone adding OnCheckedChanged="chkview_CheckedChanged" to their aspx page but when you click on the CheckBox to set its actions it does not open OnCheckedChanged="chkview_CheckedChanged". It opens SelectedIndexChanged event instead. What I am trying to do is when they select a CheckBox it adds the corresponding rows info to the TextBox. Here is what I am currently using to set the values. How can I use a selected CheckBox instead?
protected void dropGridView_SelectedIndexChanged1(object sender, EventArgs e)
{
GridViewRow row = dropdeadGridView.SelectedRow;
IDTextBox.Text = row.Cells[1].Text;
loadnumTextBox.Text = row.Cells[2].Text;
}
Once done with that how can you make it to where it will get every row that is checked instead of just one which is what is my current problem. I am looking for a way to select multiple rows and have a select button. I have done a lot of looking and can find nothing on it so I am trying to accomplish this with CheckBoxes instead. Any ideas how I can add this and get the multiple rows that can be selected. Thank you in advance.
Here is my edit* Posting asp code for CheckBox column:
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="SelectCheckBox" runat="server" OnCheckedChanged="SelectCheckBox_OnCheckedChanged"/>
</ItemTemplate>
</asp:TemplateField>
First you have to set autopostback attribute to true :
<asp:CheckBox ID="SelectCheckBox" runat="server" AutoPostBack="true"
OnCheckedChanged="SelectCheckBox_OnCheckedChanged"/>
In your case, SelectedIndexChanged is sent by the gridview. For the checkbox event you have to use OnCheckedChanged event :
protected void SelectCheckBox_OnCheckedChanged(object sender, EventArgs e)
{
CheckBox chk = sender as CheckBox ;
if(chk.Checked)
{
GridViewRow row = (GridViewRow)chk.NamingContainer;
IDTextBox.Text = row.Cells[1].Text;
loadnumTextBox.Text = row.Cells[2].Text;
}
}
If you want to loop through all selected checkboxes :
var rows = dropdeadGridView.Rows;
int count = dropdeadGridView.Rows.Count;
for (int i = 0; i < count; i++)
{
bool isChecked = ((CheckBox)rows[i].FindControl("chkBox")).Checked;
if(isChecked)
{
//Do what you want
}
}
HTML Gridview example
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" Class="table table-striped table-bordered" ShowHeaderWhenEmpty="true" HeaderStyle-HorizontalAlign="Center" RowStyle-HorizontalAlign="Center" HorizontalAlign="Center" Height="40px" Width="80%" EmptyDataText="No Stock in The Shop"> <Columns> <asp:TemplateField> <HeaderTemplate> <asp:CheckBox ID="chkAllSelect" runat="server" onclick="checkAll(this);" /> </HeaderTemplate> <ItemTemplate> <asp:CheckBox ID="chkSelect" onclick="Check_Click(this);EnableBTN(this);" runat="server" /> </ItemTemplate> </asp:TemplateField> <asp:BoundField DataField="SHOP_CODE" HeaderText="SHOP CODE" /> <asp:BoundField DataField="ITEM_CODE" HeaderText="ITEM CODE" /> <asp:BoundField DataField="ITEM_NAME" HeaderText="ITEM NAME" /> <asp:BoundField DataField="COLOR_CODE" HeaderText="COLOR CODE" /> <asp:BoundField DataField="COLOR_NAME" HeaderText="COLOR NAME" /> <asp:BoundField DataField="STOCK_NO" HeaderText="STOCK NUMBER" /> <asp:BoundField DataField="STOCK_IN_HAND" HeaderText="STOCK IN HAND" /> <asp:BoundField DataField="LOCATION_CD" HeaderText="LOCATION" /> <asp:TemplateField HeaderText="NO OF QUANTITY"> <ItemTemplate> <asp:TextBox CssClass="form-control" onkeyup="this.value=this.value.replace(/[^0-9]/g,'');" Placeholder="Enter The Correct Qty" ID="ADJqty" runat="server" AutoCompleteType="Disabled" Text=""></asp:TextBox> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView>
Use this function check all the gridview check box
function checkAll(objRef) {
var GridView = objRef.parentNode.parentNode.parentNode;
var inputList = GridView.getElementsByTagName("input");
for (var i = 0; i < inputList.length; i++) {
//Get the Cell To find out ColumnIndex
var row = inputList[i].parentNode.parentNode;
if (inputList[i].type == "checkbox" && objRef != inputList[i]) {
if (objRef.checked) {
//If the header checkbox is checked
//check all checkboxes
//and highlight all rows
row.style.backgroundColor = "#e3f1ff";
inputList[i].checked = true;
$('#DummyBTNAUTHLeave').prop('disabled', false);
$('#DummyBTNRJTLeave').prop('disabled', false);
}
else {
//If the header checkbox is checked
//uncheck all checkboxes
//and change rowcolor back to original
if (row.rowIndex % 2 == 0) {
//Alternating Row Color
row.style.backgroundColor = "rgba(0,0,0,.05)";
}
else {
row.style.backgroundColor = "white";
}
inputList[i].checked = false;
$('#DummyBTNAUTHLeave').prop('disabled', true);
$('#DummyBTNRJTLeave').prop('disabled', true);
}
}
}
}
check the specifyed checkbox in gridview
function Check_Click(objRef) {
//Get the Row based on checkbox
var row = objRef.parentNode.parentNode;
if (objRef.checked) {
//If checked change color to Aqua
row.style.backgroundColor = "#e3f1ff";
}
else {
//If not checked change back to original color
if (row.rowIndex % 2 == 0) {
//Alternating Row Color
row.style.backgroundColor = "rgba(0,0,0,.05)";
}
else {
row.style.backgroundColor = "white";
}
}
//Get the reference of GridView
var GridView = row.parentNode;
//Get all input elements in Gridview
var inputList = GridView.getElementsByTagName("input");
for (var i = 0; i < inputList.length; i++) {
//The First element is the Header Checkbox
var headerCheckBox = inputList[0];
//Based on all or none checkboxes
//are checked check/uncheck Header Checkbox
var checked = true;
if (inputList[i].type == "checkbox" && inputList[i] != headerCheckBox) {
if (!inputList[i].checked) {
checked = false;
break;
}
}
}
headerCheckBox.checked = checked;
}

Grid view row command is firing after every second click

I've shopping cart in grid view. The grid is in update panel with update mode always. The grid view is itself in a user control and this user control renders in a child page (GridView --> User Control --> Child aspx page --> master page). Whenever I click on any button to modify cart the gridview row command not fires first time but when I again click on the button second time the row command fires correctly. Now I don't know why the row command event is not firing on first click and it is firing only on every even click (second click).
ASP:
<asp:GridView ID="GVCart" runat="server" AutoGenerateColumns="False" OnRowCommand="CartUpdate">
<Columns>
<asp:BoundField DataField="Product_Name" HeaderText="Product Name">
</asp:BoundField>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="Button3" runat="server" CommandArgument='<%# Eval("Product_ID") %>'
CommandName="DecreseCartQty" Height="20px" ToolTip="Minus" AlternateText="+" />
<asp:ImageButton ID="ImageButton1" runat="server" CommandArgument='<%# Eval("Product_ID") %>'
CommandName="IncreaseCartQty" Height="20px" ToolTip="Add" AlternateText="-" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="ABC" runat="server" Text='<%# Eval("ItemQTY")+" * "+Eval("Price")+" = "+Eval("TotalPrice") %> '></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="Button4" runat="server" CommandArgument='<%# Eval("Product_ID") %>' CommandName="Remove" ToolTip="Cancel"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
C#: (in user control)
protected void CartUpdate(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "IncreaseCartQty")
{
int ProductId = Convert.ToInt32(e.CommandArgument.ToString());
DataTable CartDT = (DataTable)Session["cart"];
for (int i = 0; i < CartDT.Rows.Count; i++)
{
if (CartDT.Rows[i]["Product_ID"].ToString() == ProductId.ToString())
{
CartDT.Rows[i]["ItemQTY"] = Convert.ToInt32(CartDT.Rows[i]["ItemQTY"]) + 1;
CartDT.Rows[i]["TotalPrice"] = Convert.ToInt32(CartDT.Rows[i]["Price"]) * Convert.ToInt32(CartDT.Rows[i]["ItemQTY"]);
//Page.Response.Redirect(Page.Request.Url.ToString(), true);
}
}
}
if (e.CommandName == "DecreseCartQty")
{
int ProductId = Convert.ToInt32(e.CommandArgument.ToString());
DataTable CartDT = (DataTable)Session["cart"];
for (int i = 0; i < CartDT.Rows.Count; i++)
{
if (CartDT.Rows[i]["Product_ID"].ToString() == ProductId.ToString())
{
if (Convert.ToInt32(CartDT.Rows[i]["ItemQTY"]) > 1)
{
CartDT.Rows[i]["ItemQTY"] = Convert.ToInt32(CartDT.Rows[i]["ItemQTY"]) - 1;
CartDT.Rows[i]["TotalPrice"] = Convert.ToInt32(CartDT.Rows[i]["Price"]) * Convert.ToInt32(CartDT.Rows[i]["ItemQTY"]);
// Page.Response.Redirect(Page.Request.Url.ToString(), true);
}
}
}
}
if (e.CommandName == "Remove")
{
int ProductId = Convert.ToInt32(e.CommandArgument.ToString());
DataTable CartDT = (DataTable)Session["cart"];
for (int i = 0; i < CartDT.Rows.Count; i++)
{
if (CartDT.Rows[i]["Product_ID"].ToString() == ProductId.ToString())
{
CartDT.Rows.RemoveAt(i);
//Page.Response.Redirect(Page.Request.Url.ToString(), true);
}
}
}
}
Can anyone tell me what wrong I am doing. Your answer will be great help for me.
Thanks in advance.
It is behaving properly. You should rebind the gridview after CartUpdate so that another post back is not required.
just add these lines after
if (e.CommandName == "Remove")
{
int ProductId = Convert.ToInt32(e.CommandArgument.ToString());
DataTable CartDT = (DataTable)Session["cart"];
for (int i = 0; i < CartDT.Rows.Count; i++)
{
if (CartDT.Rows[i]["Product_ID"].ToString() == ProductId.ToString())
{
CartDT.Rows.RemoveAt(i);
//Page.Response.Redirect(Page.Request.Url.ToString(), true);
}
}
}
DataTable CartDT = (DataTable)Session["cart"];
gridview1.datasource=CartDT ;
gridview1.databind();
Checkout this answer, I think it will solve your problem. If you have your grid view in user control this issue can arise. I had a same issue when I had my grid view in a user control.

how to prevent disabled checkboxes of gridview from getting checked when select all checkbox is clicked?

I have used gridview in my aspx page.. In that i have a check box at each row including header..
By clicking the header checkbox it will check all the checkboxes including disabled checkboxes in gridview.. I need to avoid the disabled checkbox from getting checked
This is my gridview code:
<asp:GridView ID="CrowdRatingGrid" runat="server" AutoGenerateColumns="false" AllowPaging="true" PageSize="4" OnPageIndexChanging="CrowdRatingGrid_PageIndexChanging" ViewStateMode="Enabled">
<PagerSettings Mode="Numeric" PageButtonCount="4" />
<Columns>
<asp:TemplateField HeaderStyle-BackColor="#DBE2E2" HeaderStyle-Width="60px" HeaderStyle-HorizontalAlign="Center"
HeaderStyle-Height="62px">
<HeaderTemplate>
<asp:CheckBox ID="SelectAll" runat="server" onclick="SelectAll(this)" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox runat="server" ID="CheckRow" CssClass="SelectRow" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
This is my js code for selecting all checkbox:
function SelectAll(objRef) {
var GridView = objRef.parentNode.parentNode.parentNode;
var inputList = GridView.getElementsByTagName("input");
for (var i = 0; i < inputList.length; i++) {
var row = inputList[i].parentNode.parentNode;
if (inputList[i].type == "checkbox" && objRef != inputList[i]) {
if (objRef.checked) {
inputList[i].checked = true;
}
else {
inputList[i].checked = false;
}
}
}
}
Please help in achieving this? What change should i make in js to achieve my requirement?
Change condition to
if (objRef.checked && !inputList[i].disabled) {
inputList[i].checked = true;
}
else {
inputList[i].checked = false;
}

if header check box checked,then all other check box's should checked in grid view

i used this below code but it is not working..if i select header check box then all other check box should select and how to get the particular row id ,if check box is selected.
protected void headerLevelCheckBox_CheckedChanged(object sender, EventArgs e)
{
CheckBox headerChkBox = ((CheckBox)gvApproach.HeaderRow.FindControl("headerLevelCheckBox"));
if (headerChkBox.Checked == true)
{
foreach(GridViewRow gvRow in gvApproach.Rows)
{
CheckBox rowChkBox = ((CheckBox)gvRow.FindControl("rowLevelCheckBox"));
rowChkBox.Checked = true;//((CheckBox)sender).Checked;
}
}
else
{
foreach (GridViewRow gvRow in gvApproach.Rows)
{
CheckBox rowChkBox = ((CheckBox)gvRow.FindControl("rowLevelCheckBox"));
rowChkBox.Checked = false;
}
}
}
i am using vs 2008,c#
without using javascript..
aspx code...and to get the id of particular ROW IN GRID VIEW i used labe control as PhotoId (PK)
<asp:GridView ID="gvApproach" runat="server" CellPadding="4" AutoGenerateColumns="False"
GridLines="None">
<Columns>
<asp:TemplateField HeaderText="PhotoId" Visible="false">
<ItemTemplate>
<asp:Label ID="lblPhotoId" runat="server" Text='<%#Eval("PhotoId") %>' Visible="false"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox runat="server" ID="headerLevelCheckBox" AutoPostBack="true" oncheckedchanged="headerLevelCheckBox_CheckedChanged" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox runat="server" ID="rowLevelCheckBox" AutoPostBack="true"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
in code behind....
protected void headerLevelCheckBox_CheckedChanged(object sender, EventArgs e)
{
CheckBox headerChkBox = ((CheckBox)gvApproach.HeaderRow.FindControl("headerLevelCheckBox"));
if (headerChkBox.Checked == true)
{
foreach(GridViewRow gvRow in gvApproach.Rows)
{
CheckBox rowChkBox = ((CheckBox)gvRow.FindControl("rowLevelCheckBox"));
rowChkBox.Checked = true;
}
}
else
{
foreach (GridViewRow gvRow in gvApproach.Rows)
{
CheckBox rowChkBox = ((CheckBox)gvRow.FindControl("rowLevelCheckBox"));
rowChkBox.Checked = false;
}
}
}
I suggest that you don't do that on the server, and to do it on the client instead. Use javascript. Do you have jQuery present on that page (it'll be easier with that library)? Maybe this tutorial will help: https://web.archive.org/web/20210304130642/https://www.4guysfromrolla.com/articles/120810-1.aspx
To be more specific you should use something like
headerChkBox onclick="changeCheckboxes(this)"
function changeCheckboxex(mainCheck)
{
$(yourDivContainer).children("INPUT[type='checkbox']").attr('checked', yourValue);
}
Hope it helps
If you want to do it using javascript,
You should use the checkBox's tooltip attribute for holding records' ids.
For Example :
<asp:CheckBox ID="rowLevelCheckBox" runat="server" ToolTip='<%#Eval("ID")%>' />
Then ,You should use javascript code when click checkbox of header.
<script type="text/javascript">
function SelectAll(element) {
if ($(element).attr("checked")) {
$("input[type=checkbox]").attr("checked", "true");
}
else {
$("input[type=checkbox]").attr("checked", "");
}
}
</script>
<HeaderTemplate>
<div style="text-align: center; width: 100px; margin: auto">
<input type="checkbox" name="SelectAllCheckBox" onclick="SelectAll(this)">Select All</div>
</HeaderTemplate>
finally, in Code Behind.
Do you want to get selected ids, you can use this code.
public List<string> GetAllSelectedIds()
{
List<string> selectedIds= new List<string>();
for (int i = 0; i < grid.Rows.Count; i++)
{
GridViewRow row = grid.Rows[i];
if (((CheckBox)row.FindControl("rowLevelCheckBox")).Checked)
{
string rowLevelCheckBoxStr = ((CheckBox)row.FindControl("rowLevelCheckBox")).ToolTip;
selectedIds.Add(rowLevelCheckBoxStr);
}
}
return selectedIds;
}

Dynamically added controls missing during GridView RowUpdating

I have a GridView with a TemplateField column that I put PlaceHolder controls in. During the DataBound event for the GridView I dynamically add a few CheckBoxes to the PlaceHolder. That works fine and displays as expected.
My problem is that during the RowUpdating event the PlaceHolder contains no controls; my CheckBoxes are missing. I also noticed that they're missing during the RowEditing event.
I want to be able to get the values of the CheckBoxes during the RowUpdating event so I can save them to the database.
Here's some example code. I've trimmed out a lot to reduce size, but if you want to see specifics just ask and I'll be happy to add more.
HTML:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="False"
ondatabound="gridView_DataBound" onrowupdating="gridView_RowUpdating"
onrowediting="gridView_RowEditing" DataKeyNames="ID">
<Columns>
<asp:TemplateField HeaderText="Countries">
<ItemTemplate>
<asp:PlaceHolder ID="countriesPlaceHolder" runat="server"></asp:PlaceHolder>
</ItemTemplate>
<EditItemTemplate>
<asp:PlaceHolder ID="countriesPlaceHolder" runat="server"></asp:PlaceHolder>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="editButton" runat="server" CommandName="Edit" Text="Edit"></asp:LinkButton>
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="updateButton" runat="server" CommandName="Update" Text="Update"></asp:LinkButton>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code behind:
// This method works fine, no obvious problems here.
protected void gridView_DataBound(object sender, EventArgs e)
{
// Loop through the Holidays that are bound to the GridView
var holidays = (IEnumerable<Holiday>)gridView.DataSource;
for (int i = 0; i < holidays.Count(); i++)
{
// Get the row the Holiday is bound to
GridViewRow row = gridView.Rows[i];
// Get the PlaceHolder control
var placeHolder = (PlaceHolder)row.FindControl("countriesPlaceHolder");
// Create a CheckBox for each country and add it to the PlaceHolder
foreach (Country country in this.Countries)
{
bool isChecked = holidays.ElementAt(i).Countries.Any(item => item.ID == country.ID);
var countryCheckBox = new CheckBox
{
Checked = isChecked,
ID = country.Abbreviation + "CheckBox",
Text = country.Abbreviation
};
placeHolder.Controls.Add(countryCheckBox);
}
}
}
protected void gridView_RowEditing(object sender, GridViewEditEventArgs e)
{
// EXAMPLE: I'm expecting checkBoxControls to contain my CheckBoxes, but it's empty.
var checkBoxControls = gridView.Rows[e.NewEditIndex].FindControl("countriesPlaceHolder").Controls;
gridView.EditIndex = e.NewEditIndex;
BindData();
}
protected void gridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
// EXAMPLE: I'm expecting checkBoxControls to contain my CheckBoxes, but it's empty.
var checkBoxControls = ((PlaceHolder)gridView.Rows[e.RowIndex].FindControl("countriesPlaceHolder")).Controls;
// This is where I'd grab the values from the controls, create an entity, and save the entity to the database.
gridView.EditIndex = -1;
BindData();
}
This is the article that I followed for my data binding approach: http://www.aarongoldenthal.com/post/2009/04/19/Manually-Databinding-a-GridView.aspx
You need to call your BindData() method on page load.
"Dynamic controls or columns need to be recreated on every page load, because of the way that controls work. Dynamic controls do not get retained so you have to reload them on every page postback; however, viewstate will be retained for these controls."
See Cells in gridview lose controls on RowUpdating event
Also in the article you linked, there is an ItemTemplate and an EditItemTemplace because they have different displays, i.e. read only and editable. Yours are the same so I think you could simplify your design:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" ondatabound="gridView_DataBound">
<Columns>
<asp:TemplateField HeaderText="Countries">
<ItemTemplate>
<asp:PlaceHolder ID="countriesPlaceHolder" runat="server"></asp:PlaceHolder>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="editButton" runat="server" Text="Edit" onclick="editButton_Click" ></asp:LinkButton>
<asp:LinkButton ID="updateButton" runat="server" Text="Update" onclick="updateButton_Click" ></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code Behind:
protected void gridView_DataBound(object sender, EventArgs e)
{
// Loop through the Holidays that are bound to the GridView
var holidays = (IEnumerable<Holiday>)gridView.DataSource;
for (int i = 0; i < holidays.Count(); i++)
{
// Get the row the Holiday is bound to
GridViewRow row = gridView.Rows[i];
// Get the PlaceHolder control
var placeHolder = (PlaceHolder) row.FindControl("countriesPlaceHolder");
var countryCheckBox = new CheckBox
{
Checked = true,
ID = "auCheckBox",
Text = "Aus",
Enabled = false
};
placeHolder.Controls.Add(countryCheckBox);
var editButton = (LinkButton)row.FindControl("editButton");
editButton.CommandArgument = i.ToString();
var updateButton = (LinkButton)row.FindControl("updateButton");
updateButton.CommandArgument = i.ToString();
updateButton.Visible = false;
}
}
protected void editButton_Click(object sender, EventArgs e)
{
LinkButton editButton = (LinkButton) sender;
int index = Convert.ToInt32(editButton.CommandArgument);
GridViewRow row = gridView.Rows[index];
// Get the PlaceHolder control
LinkButton updateButton = (LinkButton)row.FindControl("updateButton");
updateButton.Visible = true;
editButton.Visible = false;
CheckBox checkbox = (CheckBox)row.FindControl("auCheckBox");
if (checkbox != null)
{
checkbox.Enabled = true;
// Get value and update
}
}
protected void updateButton_Click(object sender, EventArgs e)
{
LinkButton updateButton = (LinkButton)sender;
int index = Convert.ToInt32(updateButton.CommandArgument);
GridViewRow row = gridView.Rows[index];
// Get the PlaceHolder control
LinkButton editButton = (LinkButton)row.FindControl("updateButton");
editButton.Visible = true;
updateButton.Visible = false;
CheckBox checkbox = (CheckBox)row.FindControl("auCheckBox");
if (checkbox != null)
{
// Get value and update
checkbox.Enabled = false;
}
}
If you want to be it enabled from the get go, just remove the enabled checks and you can delete your edit button.
Hope that helps.

Categories