Not able to access dynamically generated templated field controls - c#

I am creating dynamic Template Fields for my gridview:
<asp:GridView ID="grdData" runat="server" DataKeyNames = "ID" AutoGenerateColumns="false" OnRowDataBound="grdData_RowDataBound">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="chkAll" AutoPostBack="true" OnCheckedChanged="OnCheckedChanged" runat="server" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="editbtn" AutoPostBack="true" OnCheckedChanged="OnCheckedChanged" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
the code to add templateField is below:
private void BindGridView(DataTable dtData)
{
foreach (DataColumn item in dtData.Columns)
{
TemplateField tfield = new TemplateField();
tfield.HeaderText = item.ToString();
grdData.Columns.Add(tfield);
}
grdData.DataSource = dtData;
ViewState["dtDataTable"] = dtData;
grdData.DataBind();
}
and in row databound I am adding textbox and label to the templatefield:
protected void grdData_RowDataBound(object sender, GridViewRowEventArgs e)
{
DataTable dtData = (DataTable)ViewState["dtDataTable"];
if (e.Row.RowType == DataControlRowType.DataRow)
{
int i = 1;
foreach (DataColumn item in dtData.Columns )
{
TextBox txtBox = new TextBox();
txtBox.ID = "txt"+item.ToString();
txtBox.Text = (e.Row.DataItem as DataRowView).Row[item.ToString()].ToString();
txtBox.Visible = false;
e.Row.Cells[i].Controls.Add(txtBox);
Label lblBox = new Label();
lblBox.ID = "lbl" + item.ToString();
lblBox.Text = (e.Row.DataItem as DataRowView).Row[item.ToString()].ToString();
e.Row.Cells[i].Controls.Add(lblBox);
i++;
}
}
}
Everything is working good so far,The grid is getting created and the values are getting populated ,but when i am calling below method and try to access the gridview control ,its throwing object reference error:
protected void OnCheckedChanged(object sender, EventArgs e)
{
bool isUpdateVisible = false;
CheckBox chk = (sender as CheckBox);
if (chk.ID == "chkAll")
{
foreach (GridViewRow row in grdData.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
row.Cells[0].Controls.OfType<CheckBox>().FirstOrDefault().Checked = chk.Checked;
}
}
}
CheckBox chkAll = (grdData.HeaderRow.FindControl("chkAll") as CheckBox);
chkAll.Checked = true;
foreach (GridViewRow row in grdData.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
bool isChecked = row.Cells[0].Controls.OfType<CheckBox>().FirstOrDefault().Checked;
for (int i = 1; i < row.Cells.Count; i++)
{
Label test= row.FindControl("lblName") as Label;//this is coming null
Below code lines are throwing object reference error as they are not able to find control
row.Cells[i].Controls.OfType<Label>().FirstOrDefault().Visible = !isChecked;//this line throwing object reference error
if (row.Cells[i].Controls.OfType<TextBox>().ToList().Count > 0)
{
row.Cells[i].Controls.OfType<TextBox>().FirstOrDefault().Visible = isChecked;
}
if (row.Cells[i].Controls.OfType<DropDownList>().ToList().Count > 0)
{
row.Cells[i].Controls.OfType<DropDownList>().FirstOrDefault().Visible = isChecked;
}
if (isChecked && !isUpdateVisible)
{
isUpdateVisible = true;
}
if (!isChecked)
{
chkAll.Checked = false;
}
}
}
}
btnUpdate.Visible = isUpdateVisible;
}
Edit:
I tried reinistialising the controls in preinit event but still no luck:
protected void Page_PreInit(object sender, EventArgs e)
{
if (ViewState["gridData"] != null)
{
BindGridView((DataTable)ViewState["gridData"]);
}
}
What I am doing wrong?

I recreated the dynamic gridview Controls in OnRowCreated as this event gets called in every postback instead of onRowDataBound Event and it worked like charm.

Related

Disable a row in gridview based on column name

I am using the below code to disable row in gridview where the column name is test. Everything works fine except for the first row. The color does not get applied to the first row. Where am I going wrong?I also want to hide a column based on column name.
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (Hidden4.Value == "Data Present")
{
foreach (GridViewRow item in GdvTestData.Rows)
{
int a = GetColumnIndexByName(item, "test");
int b = GetColumnIndexByName(item, "id");
if (e.Row.RowType == DataControlRowType.DataRow)
{
string test = e.Row.Cells[a].Text;
foreach (TableCell cell in e.Row.Cells)
{
if (test == "Y")
{
cell.BackColor = Color.Gray;
e.Row.Attributes.Add("onmouseover", "alert('This data is for testing');");
}
}
e.Row.Cells[b].Visible = false;
}
}
}
}
Maybe you are confusing data/business logic and UI.
RowDataBound event works per row so you don't need to loop gridview rows.
You are working on cell content but you have data bound to those. So:
ASPX
<asp:GridView runat="server" ID="gv" ...
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label runat="server" Text='<%# Eval("Test") %>' />
</ItemTemplate>
</asp:TemplateField>
...
Code Behind
private void GrdBind()
{
// populate datatable
gv.DataSource = myDataTable;
gv.Databind();
}
And the databound event:
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (Hidden4.Value == "Data Present")
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRow row = ((DataRowView)e.Row.DataItem).Row;
string test = row.Field<String>("Test");
if (test== "Y")
{
e.Row.Cells[0].BackColor = Color.Gray; // set your index
e.Row.Attributes.Add("onmouseover", "alert('This data is for testing');");
}
}
}
}
You can do this. Although I don't understand what you mean by disabling a row.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//check if the row is a datarow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//cast the dataitem back to a datarowview
DataRowView row = e.Row.DataItem as DataRowView;
//find the column value in the row, not the cell text
string test = row["columnName"].ToString();
//check the value and if so apply backcolor
if (test == "Y")
{
e.Row.BackColor = Color.Red;
//or hide the row (no need to do this in Databind or OnPreRender)
e.Row.Visible = false;
}
}
}

Getting gridview checked boxes

I have this template field
<asp:TemplateField ItemStyle-Width="40px">
<HeaderTemplate>
<asp:CheckBox ID="chkboxSelectAll" runat="server" AutoPostBack="true" OnCheckedChanged="chkboxSelectAll_CheckedChanged" />
</HeaderTemplate>
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" />
<ItemTemplate>
<asp:CheckBox ID="chkEmp" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="False">
In the code-behind I have this code:
protected void chkboxSelectAll_CheckedChanged(object sender, EventArgs e)
{
CheckBox ChkBoxHeader = (CheckBox)grdGeral.HeaderRow.FindControl("chkboxSelectAll");
foreach (GridViewRow row in grdGeral.Rows)
{
CheckBox ChkBoxRows = (CheckBox)row.FindControl("chkEmp");
if (ChkBoxHeader.Checked == true)
{
ChkBoxRows.Checked = true;
}
else
{
ChkBoxRows.Checked = false;
}
}
}
protected void btnLista_Click(object sender, EventArgs e)
{
string strEmailTotal = "";
string strEmail = "";
foreach (GridViewRow row in grdGeral.Rows)
{
CheckBox chkBx = (CheckBox)grdGeral.FindControl("chkEmp");
if (chkBx != null)
{
if (chkBx.Checked)
{
strEmail = ((Label)grdGeral.FindControl("lblEmail")).Text;
strEmailTotal = strEmailTotal + "," + strEmail;
}
}
}
lblMail.Text = strEmailTotal ;
}
I always get a null value for the checkbox, even if I set the default value to "true" in the templatefield. Can anyone help me with this?
Thank you
In your btnLista_Click event you should use row instead grdGeral:
CheckBox chkBx = (CheckBox)row.FindControl("chkEmp");
And below this the same:
strEmail = ((Label)row.FindControl("lblEmail")).Text;
try this solution.
foreach (GridViewRow row in grdGeral.Rows)
{
CheckBox chkBx = row.FindControl("chkEmp") as CheckBox ;
}

Integer only validation for dynamically added Textbox inside Asp.net Gridview

Below is how my GridView code , since the datatable is a pivoted value so the number of columns cannot be predicted. So I am adding textbox dynamically through code.
<asp:GridView ID="gvData"
EmptyDataText="There are no data records to display."
runat="server" AutoGenerateColumns="false"
HeaderStyle-BackColor="#3AC0F2"
HeaderStyle-ForeColor="White" OnRowDataBound="gvData_RowDataBound" >
<RowStyle BorderColor="LightBlue" />
</asp:GridView>
protected void Page_Load(object sender, EventArgs e)
{
foreach (var item in columnNames)
{
TemplateField tfield = new TemplateField();
tfield.HeaderText = item;
gvData.Columns.Add(tfield);
}
gvData.DataSource = ds.Tables[0];
gvData.DataBind();}
protected void gvData_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 3; i < columnNames.Length; i++)
{
TextboxCount++;
TextBox txtName = new TextBox();
txtName.ID = "txt" + Convert.ToString(TextboxCount);
txtName.BorderStyle = BorderStyle.None;
txtName.Text = (e.Row.DataItem as DataRowView).Row[columnNames[i]].ToString();
e.Row.Cells[i].Controls.Add(txtName); }}}
Now when user try to change value in the textbox I have to validate that they only enter integer value.
Here I am not sure what has to be done.
You can use int.TyrParse method
Example
int number;
string s = "AA";
bool IsInteger = int.TryParse(s, out number);
You could use javascript function and that to textbox from code behind like:
// Add this gvData_RowDataBound , allownumbers is a javascript function
txtName.Attributes.Add("onkeypress", "javascript:return allownumbers(event);");
Or else if you are using .NET 4.5 version then try out this:
txtName.Attributes["type"] = "number";

TemplateControl Checkbox Event in Custom GridView Control

I have a custom GridView Control where I grab data from the database to populate the control. On the page I have also created a HeaderTemplate checkbox control and an ItemTemplate checkbox control:
<nm:ContactGridViewControl runat="server" ID="grdContacts">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox runat="server" AutoPostBack="true" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</nm:ContactGridViewControl>
I populate the GridView as follows in the OnInit event. I Chose not to repopulate on every postback because it was slowing down the app.
protected override void OnInit(EventArgs e)
{
this.RowDataBound += new GridViewRowEventHandler(ContactGridViewControl_RowDataBound);
this.RowCreated += new GridViewRowEventHandler(ContactGridViewControl_RowCreated);
if (!Page.IsPostBack)
{
List<EnquiryItem> contactList = new List<EnquiryItem>();
DataTable list = new DataTable();
if (SessionManager.LoginState != null)
{
contactList = SiteDataLayerHandler.GetContactList(SessionManager.LoginState.UserID);
}
if (contactList != null)
{
list.Columns.Add("LeadID");
list.Columns.Add("Name");
list.Columns.Add("Email Address");
foreach (EnquiryItem item in contactList)
{
DataRow row = list.NewRow();
row["LeadID"] = item.LeadID;
row["Name"] = string.Format("{0} {1}", item.FirstName.ToCapitalize(), item.LastName.ToCapitalize());
row["Email Address"] = item.EmailAddress;
list.Rows.Add(row);
}
this.DataSource = list;
this.DataBind();
}
}
base.OnInit(e);
}
In order to keep all code associated with the control in one place I have added a 'CheckedChanged' event dynamically on 'OnRowDataBound' This is just for the Checkbox in the HeaderTemplate. The Reason is so I can use this checkbox as a 'Select/Deselect All Rows':
protected void ContactGridViewControl_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex == -1) // Check if row is Header row
{
CheckBox chk = e.Row.GetAllControls().OfType<CheckBox>().FirstOrDefault();
if (chk != null)
{
chk.CheckedChanged += new EventHandler(chk_CheckedChanged);
}
}
}
I then have the event code on the same page like so:
protected void chk_CheckedChanged(object sender, EventArgs e)
{
bool isChecked = ((CheckBox)sender).Checked;
foreach (GridViewRow row in this.Rows)
{
CheckBox chkBox = row.Cells[0].Controls[0] as CheckBox;
if (chkBox != null)
{
chkBox.Checked = isChecked;
}
}
}
This is where the problems start. My event never gets hit! However, the checkbox does postback.
Ok so the answer is this. I needed to assign the CheckedChanged event on the 'OnRowCreated' event instead of 'OnRowDataBound'
protected override void OnRowCreated(GridViewRowEventArgs e)
{
if (e.Row.RowIndex == -1)
{
CheckBox chk = e.Row.GetAllControls().OfType<CheckBox>().FirstOrDefault();
if (chk != null)
{
chk.CheckedChanged += new EventHandler(chk_CheckedChanged);
}
}
base.OnRowCreated(e);
}
This way the event hits the method everytime

How do I change the background color of a row in a GridView if a checkbox in the row is enabled?

I would like to change the background color of all the rows with value for "active" column unchecked in a GridView. I tried the following way but it doesn't work:
protected void GdvDetails_RowDataBound(object sender, GridViewRowEventArgs e)
{
CheckBox chkItem = null;
foreach (GridViewRow grRow in GdvDetails.Rows)
{
if (grRow.RowType == DataControlRowType.DataRow)
{
chkItem = (CheckBox)grRow.Cells[6].FindControl("active");
if (chkItem.Checked )
{
grRow.BackColor = Color.Red;
}
}
}
}
The error message is "Object reference not set to an instance of an object."
Your code doesn't work because you need to do it on RowDataBund
protected void CustomersGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
//Paste your code here.
}
}
And add a handler for RowDataBound as so:
<asp:gridview id="CustomersGridView"
allowpaging="true"
onrowdatabound="CustomersGridView_RowDataBound"
runat="server">
</asp:gridview>
You need to handle RowDataBound event instead of DataBound event, so put you in RowDataBound event as below:
In aspx page, after added the event the code will look like:
<asp:gridview id="GdvDetails"
onrowdatabound="GdvDetails_RowDataBound"
runat="server">
</asp:gridview>
In code behind(.cs):
protected void GdvDetails_RowDataBoundd(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
CheckBox chkItem = (CheckBox)e.Row.FindControl("active");
if (chkItem.Checked)
{
GdvDetails.SelectedRow.BackColor = Color.LightGray;
}
}
}
So this WORKS :)
protected void GdvDetails_DataBound(object sender, EventArgs e)
{
CheckBox chkItem = null;
foreach (GridViewRow grRow in GdvDetails.Rows)
{
if (grRow.RowType == DataControlRowType.DataRow)
{
chkItem = (CheckBox)grRow.Cells[6].FindControl("CkbActive");
bool bl = chkItem.Checked;
if (bl == false)
{
grRow.BackColor = Color.LightGray;
}
}
}
}
And the aspx file has
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID= "CkbActive" Checked ='<%# Bind ("active") %>' Enabled="false" runat="server"/>
</ItemTemplate>
</asp:TemplateField>
in the GridView GdvDetails.
i didn't use the code under onrowdatabound because its an event for each row and i thought it will iterate unnecessarily. And this works... just in case anyone else is fumbling like me?!! thx for all the help

Categories

Resources