Dynamically added controls missing during GridView RowUpdating - c#

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.

Related

How to pass value to textbox in grid view using JavaScript by popup window?

How to get selected textbox index? How to get access of particular row?
var grid = document.getElementById("<%= GridView1.ClientID%>");
for (var i = 0; i < grid.rows.length - 1; i++) {
var txtAmountReceive = $("input[id*=TextBox2]")
txtAmountReceive[i].value="hello"
txtAmountReceive[i].Text = "hello";
var popup = window.open("Default3.aspx", "Popup", "width=300,height=100");
document.getElementById('<%= GridView1.ClientID %>').Text = "hello";
popup.focus();
}
Ans: How to get access of particular row
protected void ShowPolicy_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == ("Proceed"))
{
GridViewRow row = (GridViewRow)((Button)e.CommandSource).NamingContainer;
int currentRowIndex = Int32.Parse(e.CommandArgument.ToString());
txtBoxId.Text = Convert.ToString(ShowPolicy.DataKeys[currentRowIndex].Value);
txtAnotherBox.Text = Convert.ToString(row.Cells[1].Text)
//Similarly you can do for other cells.
}
}
File.aspx
<asp:GridView ID="ShowPolicy" runat="server" HorizontalAlign="Center"
onrowcommand="ShowPolicy_RowCommand" DataKeyNames="PolicyNumber">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="ButtonProceed" runat="server" Text="ProceedToEdit" CommandName="Proceed" CommandArgument='<%#Eval("PolicyNumber") %>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
As per my understand your popup page and grid view page both are different.
If you want to pass value from one page to another page using javascript then you can use localStorage
Default3.aspx
localStorage.setItem("KeyForAccess", "YourValue");
Gridview page
var txtAmountReceive = $("input[id*=TextBox2]")
txtAmountReceive[i].value=localStorage.getItem("KeyForAccess");
txtAmountReceive[i].Text =localStorage.getItem("KeyForAccess");
FYI : It will require HTML5

How to get CheckBox value from GridView when CheckBox selected

I have GridView filled automatically as
<asp:GridView ID="gvValues" runat="server"
OnRowDataBound="gvValues_RowDataBound"
OnPageIndexChanging="gvValues_PageIndexChanging"
<Columns>
<asp:TemplateField HeaderText="#">
<ItemTemplate>
<%# gvValues.PageSize*gvValues.PageIndex+ Container.DisplayIndex+1 %>
<asp:CheckBox ID="chkProduct" runat="server" CssClass="chkProduct"/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="online" meta:resourcekey="Online">
<ItemTemplate >
<asp:CheckBox ID="chkProductonline" runat="server" OnCheckedChanged ="chkProductonline_CheckedChanged" AutoPostBack="true"/>
</ItemTemplate>
</asp:TemplateField>
What I need is when I click on the chkProductonline checkbox, to fire an event and get the chkProductonline and chkProducton values. I have tried this but it always gives me null.
protected void chkProductonline_CheckedChanged(object sender, EventArgs e)
{
var chkProductonline = FindControl("chkProductonline") as CheckBox;
// bool ischeck = chkProductonline.Checked;
var chkProduct = gvValues.FindControl("chkProduct") as CheckBox;
}
I can't loop the GridView. I need to do this one-by-one. Is there another way to do that?
You can try this:
protected void chkProductonline_CheckedChanged(object sender, EventArgs e)
{
CheckBox chkProductonline = sender as CheckBox;
...
CheckBox chkProduct = chkProductionLine.NamingContainer.FindControl("chkProduct") as CheckBox;
...
}
You need to call FindControl on a specific row. You will not be able to call it on the entire GridView because there exists repeating content (i.e. multiple chkProductionlines and chkProducts). A row knows of its checkboxes, and not of the others.
So what you can do is first get the CheckBox that called the event (your sender parameter, chkProductionline) and use its NamingContainer. Since it is contained in a GridView row, cast the row as such as use it to find the other controls you may need.
protected void chkProductonline_CheckedChanged(object sender, EventArgs e)
{
CheckBox chkProductionline = (CheckBox)sender;
GridViewRow row = (GridViewRow)chkProductionline.NamingContainer;
CheckBox chkProduct = (CheckBox)row.FindControl("chkProduct");
}

Get data from dynamically created controls in TemplateFields for gridview

I have a webpage that has a gridview which is bound to a list of custom objects but also has 1 dynamically created TemplateFields. These fields are created at Page_PreRender and can be a textbox or dropdownlist based on the object in the list. I have a button at the bottom of the page that needs to save all the data inputed in the dynamic objects when pressed. When i try to find the dynamic control i am unable to do so using the FindControl() method. It always comes back blank.
How can i retrieve the user entered/selected data?
This is my gridview
<div id="divSearchCriteriaGrid" runat="server" class="padding-top-15">
<asp:GridView ID="gvSearchCriteria" runat="server" AutoGenerateColumns="False" OnRowDataBound="gvSearchCriteria_OnRowDataBound" GridLines="None">
<Columns>
<asp:BoundField DataField="SearchFieldId" Visible="False" />
<asp:TemplateField HeaderText="Search Field">
<ItemTemplate>
<asp:CheckBox ID="cbDisplay" runat="server" AutoPostBack="False" onclick="ToggleCriteriaControls(this)" />
</ItemTemplate>
<ItemStyle Width="25%" />
</asp:TemplateField>
<asp:TemplateField HeaderText="Begin Criteria">
<ItemStyle Width="35%" />
</asp:TemplateField>
<asp:TemplateField HeaderText="End Criteria">
<ItemStyle Width="35%" />
</asp:TemplateField>
<asp:BoundField DataField="ControlTypeId" Visible="False" />
</Columns>
</asp:GridView>
</div>
And this is my code behind for creating the controls:
public void Page_PreRender(object sender, EventArgs e)
{
TryAction(PrepareLoad);
}
private void PrepareLoad()
{
if (IsPostBack) return;
BindData();
}
private void BindData()
{
gvSearchCriteria.DataSource = null;
gvSearchCriteria.DataSource = SearchFieldList;
gvSearchCriteria.DataBind();
}
protected void gvSearchCriteria_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
SearchField searchField = e.Row.DataItem as SearchField;
if (searchField != null)
{
e.Row.Cells[0].Text = searchField.SearchFieldId.ToString();
e.Row.Cells[4].Text = searchField.ControlTypeId.ToString();
CheckBox checkBox = (CheckBox)e.Row.FindControl("cbDisplay");
checkBox.Text = searchField.FieldDescription;
checkBox.Checked = searchField.Checked;
checkBox.Enabled = true;
if (searchField.ControlTypeId.ToString() == "1")
{
RadTextBox textBox = new RadTextBox();
textBox.ID = "txtBoxBegin";
e.Row.Cells[2].Controls.Add(textBox);
textBox = new RadTextBox();
textBox.ID = string.Format("txt{0}End", searchField.SearchFieldId);
e.Row.Cells[3].Controls.Add(textBox);
}
else if (searchField.ControlTypeId.ToString() == "2")
{
RadComboBox comboBox = new RadComboBox();
comboBox = new SearchService().GetRadComboBoxById(searchField.SearchFieldId);
comboBox.ID = string.Format("cbo{0}Begin", searchField.SearchFieldId);
e.Row.Cells[2].Controls.Add(comboBox);
}
}
}
}
This all works good and the controls get created with the checkbox.
Here is my code for trying to loop through each row of the gridview to get the user entered data which does not work.
private void Save()
{
foreach (GridViewRow row in gvSearchCriteria.Rows)
{
CheckBox include = (CheckBox)row.FindControl("cbDisplay");
int id, controlTypeId;
string criteriaOne = string.Empty;
string criteriaTwo = string.Empty;
if (!include.Checked) continue;
id = int.Parse(row.Cells[0].Text);
if (controlTypeId == "1")
{
RadTextBox radTextBox = (RadTextBox) row.FindControl("txtBoxBegin");
if (radTextBox != null)
{
criteriaOne = radTextBox.Text;
}
radTextBox = (RadTextBox)row.FindControl("txtBoxEnd");
if (radTextBox != null)
{
criteriaTwo = radTextBox.Text;
}
}
else if(controlTypeId == "2")
{
RadComboBox radComboBox = (RadComboBox)row.FindControl(string.Format("cbo{0}Begin",id));
if (radComboBox != null)
{
criteriaOne = radComboBox.SelectedValue;
}
}
}
}
The radTextBox and radComboBox variables i am trying to get using the FindControlId always comes back null.
cell 0 comes back ok each time with the correct Id. the cbDisplay checkbox always returns whether the row is checked or not and cell 4 gets the ControlTypeId just fine. It is the TemplateFields that i cannot get the values for.
Any help is greatly appreciated.
I was able to get the information from the dynamic controls once i moved the BindData() function to the Page_Init instead of the Page_PreRender().

Unable to delete multiple grid view records

I am trying to delete multiple grid view records. I tried as shown below.
public void btnDelete_Click(object sender, EventArgs e)
{
StringCollection orderNumberCollection = new StringCollection();
if (gridOrders.Rows.Count > 0)
{
foreach (GridViewRow gvrow in gridOrders.Rows)
{
if (gvrow.RowType == DataControlRowType.DataRow) {
CheckBox cbx = (CheckBox)gvrow.Cells[0].FindControl("chkdelete");
Label lblOrderNumner = (Label)gvrow.FindControl("labelOrderNumber");
Label lastName = (Label)gvrow.FindControl("LabelLastName");
if (cbx.Checked && lblOrderNumner != null)
{
orderNumberCollection.Add(lblOrderNumner.Text);
}
}
}
}
if (orderNumberCollection.Count > 0)
{
DeleteMultipleOrders(orderNumberCollection);
}
}
But always check box control showing "Checked = false". Why check box control always showing false even I checked some of the check boxes?
Here is my Grid view code:
<asp:TemplateField>
<HeaderTemplate>
<table><tr><td ><asp:CheckBox ID="chkAll" runat="server" /></td><td><asp:Button ID="btnDelete" runat="server" Text="Delete" OnClick="btnDelete_Click" /></td></tr></table>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkdelete" runat="server" Text='<%# Bind("OrderNumber") %>' Font-Bold="false" />
</ItemTemplate>
</asp:TemplateField>
I'm with Tim on this, it sounds like you are loading your gridview from within Page_Load, which is fine. but in your case you would need to make sure your gridview loading code looks like this:
if(!Page.IsPostBack)
{
//gridview loading code
}
this prevents your gridview from being reloaded (and losing which boxes are checked) when you click your delete button

Grid view Edit issue

I have editable grid view, If I click on edit in any row say "x", it opens in edit mode, however if I click on any other row, say "y", "x" should cancel edit. But In my code after clicking on "y", both the rows remains in edit mode.
protected void gvViewAdmins_RowEditing(object sender, GridViewEditEventArgs e)
{
gvViewAdmins.EditIndex = e.NewEditIndex;
Label lblEmailId = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvlblEmail") as Label;
lblEmailId.Visible = false;
ViewState["currentEmailId"] = lblEmailId.Text;
TextBox textboxEmailId = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvtbEmailId") as TextBox;
textboxEmailId.Text = ViewState["currentEmailId"].ToString();
textboxEmailId.Visible = true;
Label lblRole = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvlblRole") as Label;
lblRole.Visible = false;
ViewState["currentRole"] = lblRole.Text;
DropDownList dropdownRoles = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvddlRoles") as DropDownList;
this.PopulateRole(dropdownRoles);
dropdownRoles.Visible = true;
this.SelectRoleDropDownValue(dropdownRoles);
LinkButton lbtnUpdate = gvViewAdmins.Rows[e.NewEditIndex].FindControl("lbtnUpdate") as LinkButton;
LinkButton lbtnCancel = gvViewAdmins.Rows[e.NewEditIndex].FindControl("lbtnCancel") as LinkButton;
LinkButton lbtnEdit = gvViewAdmins.Rows[e.NewEditIndex].FindControl("lbtnEdit") as LinkButton;
lbtnUpdate.Visible = true;
lbtnCancel.Visible = true;
lbtnEdit.Visible = false;
}
What is wrong in my code?
After looking at your code, It seems that, you are not using gridview's default edit functionality. You are just setting controls visible property on and off.
Better way is, Define ItemTemplate and Edit Item Template Separately like,
Markup:
<asp:GridView ID="objGridView" runat="server" AutoGenerateColumns="false" onRowEditing="objGridView_RowEditing">
<columns>
<asp:TemplateField HeaderText="">
<ItemTemplate>
<asp:Label ID="lblEmailID" runat="server" Text='<%#Eval("<<EmailID Field>>")%>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtEmailID" runat="server" Text='<%#Eval("<<EmailID Field>>")%>'/>
</EditItemTemplate>
</asp:TemplateField>
</columns>
</asp:GridView>
Code Behind:
protected void objGridView_RowEditing(object sender, GridViewEditEventArgs e)
{
objGridView.EditIndex = e.NewEditIndex;
<<BindGrid Again>>
}

Categories