TemplateControl Checkbox Event in Custom GridView Control - c#

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

Related

Not able to access dynamically generated templated field controls

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.

How to add data to GridView?

I'm trying to add data by following code:
protected void gridview1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (Session["BranchingCode"] != null)
{
List<CourseDetail> studentList = Course_Detail.GetStudentListOfBranch(Session["BranchingCode"].ToString(), Session["CurrentSession"].ToString());
if (studentList != null)
{
for (int i = 0; i < studentList.Count(); i++)
{
e.Row.Cells[0].Text = studentList[i].UserNameRoll;
e.Row.Cells[1].Text = studentList[i].StudentName;
}
}
}
GridView1.DataBind();
}
}
But as there is no datasource attached to Gridview,This event doesn't fire.
Please tell me what to do?
Is there anyway to fire this event forcefully or do something else & enter data somewhere else..?
You misuse this event and you should not call if forcefully.
First of all somewhere in page_load event load your data and bind it to grid:
if (Session["BranchingCode"] != null)
{
List<CourseDetail> studentList = Course_Detail.GetStudentListOfBranch(Session["BranchingCode"].ToString(), Session["CurrentSession"].ToString());
if (studentList != null)
{
GridView1.DataSource = studentList;
GridView1.DataBind();
}
}
This will bind your student list to grid. Now we have to handle displaying data on grid, there are more than one ways to do that but this should be enough for you:
In your html, xxx.aspx page where you are declaring your GridView do this:
<asp:GridView ID="GridView1" runat="server" ...... >
<Columns>
<asp:BoundField HeaderText="User Name Roll" DataField="UserNameRoll" />
<asp:BoundField HeaderText="Student Name" DataField="StudentName" />
</Columns>
</asp:GridView>

asp:GridView - change checkbox status when click anywhere in the line

I have a web app and use gridview to show some SQL data. In the GV I have a checkbox in the first column. As suggested in the title, I want to check the checkbox when user clicks anywhere in that line. How can I accomplish that. Thanks.
This is my GV;
<asp:GridView ID="myGV" runat="server" AutoGenerateColumns="False" DataKeyNames="ID"
OnRowDataBound="myGV_OnRowDataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="myCB" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" />
I use this code to highlight the row when mouse pointer is over it;
protected void myGV_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
{
e.Row.Attributes.Add("onmouseover", "this.originalstyle=this.style.backgroundColor;this.style.backgroundColor='#D9ECFB'");
e.Row.Attributes.Add("onmouseout", "this.style.backgroundColor=this.originalstyle;");
}
}
EDIT:
I added "OnSelectedIndexChanging" and "OnSelectedIndexChanged" to the GridView and then tried this (as suggested by Ravi), but couldn't get it to work.
protected void myGV_SelectedIndexChanging(Object sender, GridViewSelectEventArgs e)
{
GridViewRow row = myGV.Rows[e.NewSelectedIndex];
CheckBox chk = (CheckBox)myGV.FindControl("cbIzpis");
if (chk.Checked == true)
{
chk.Checked = false;
}
else if (chk.Checked == false)
{
chk.Checked = true;
}
}
protected void myGV_SelectedIndexChanged(Object sender, EventArgs e)
{
GridViewRow row = nyGV.SelectedRow;
}
you can use GridView.SelectedRow property, with SelectedIndexChanged Event, Gridview Selected Row
void CustomersGridView_SelectedIndexChanged(Object sender, EventArgs e)
{
// Get the currently selected row using the SelectedRow property.
GridViewRow row = CustomersGridView.SelectedRow;
MessageLabel.Text = "You selected " + row.Cells[2].Text + ".";
}
void CustomersGridView_SelectedIndexChanging(Object sender, GridViewSelectEventArgs e)
{
// SelectedIndexChanging event occurs before the select operation in the GridView control, the
// SelectedRow property cannot be used. Instead, use the Rows collection
// and the NewSelectedIndex property of the e argument passed to this
// event handler.
GridViewRow row = CustomersGridView.Rows[e.NewSelectedIndex];
// here you can check the checkbox, by accessing it in template column using findControl method
CheckBox chk = (CheckBox) CustomersGridview.FindControl("chkboxID");
chk.checked;
if (row.Cells[1].Text == "SomeCondition")
{
e.Cancel = true;
MessageLabel.Text = "You cannot select " + row.Cells[2].Text + ".";
}
}

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

Determining a which checkbox is checked on a datagrid and updating DB

I have a datagrid with a TemplateField and checkbox in this field. I will marking these check boxes as either checked or not depending on a 1 or 0 in the database.
<asp:TemplateField HeaderText="Normal User Logging">
<ItemTemplate>
<asp:CheckBox runat="server" ID="normalLogging" Checked='<%# Eval("normal_toggle") == 1 %>'
AutoPostBack="true" />
</ItemTemplate>
</asp:TemplateField>
I will have multiple rows in this datagrid. I am wondering how I will determine which checkbox is checked whenever one is checked. Such as, how do I know a person clicked on the third row checkbox?
you create your column with a DataGridViewCheckBoxColumn control type, and use the Click events and CellContentClick, see example below
private void Form1_Load(object sender, EventArgs e)
{
DataGridViewCheckBoxColumn col = new DataGridViewCheckBoxColumn();
col.Name = "ColumnName";
col.HeaderText = "HeaderTest";
col.TrueValue = "True";
col.FalseValue = "False";
this.dataGridView1.Columns.Add(col);
this.dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);
this.dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (this.dataGridView1.Columns[e.ColumnIndex].Name == "ColumnName")
{
DataGridViewCheckBoxCell cell = this.dataGridView1.CurrentCell as DataGridViewCheckBoxCell;
if (cell.Value == cell.TrueValue)
//your code here
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex >= 0 && this.dataGridView1.Columns[e.ColumnIndex].Name == "ColumnName")
{
DataGridViewCheckBoxCell cell = this.dataGridView1.CurrentCell as DataGridViewCheckBoxCell;
if (cell.Value == cell.TrueValue)
{
//your code here
}
}
}
Regards
Based on what you stated, it's not the Checkboxes which will perform the PostBack, but some other button, So you can check your whole selection at once. In that case, Checkboxes should not be AutoPostBack="true".
That said, your Button's code would be something like this:
foreach (GridViewRow row in gv.Rows)
{
CheckBox cb = row.FindControl("cb") as CheckBox;
if (cb != null)
{
if(cb.Checked)
{
//Do your thing here
}
}
}
Update
OP (Justin) posted that he wants to update DB for each CheckBox click. In that case, the solution is handle the CheckBox's OnCheckedChanged event:
Aspx Code:
<asp:TemplateField HeaderText="Normal User Logging">
<ItemTemplate>
<asp:CheckBox runat="server" ID="normalLogging"
Checked='<%# Eval("normal_toggle") == 1 %>'
AutoPostBack="true"
OnCheckedChanged="cb_CheckedChanged"
yourID='<%#Eval("yourIdField") %>'/>
</ItemTemplate>
</asp:TemplateField>
C# Code Behind:
protected void cb_CheckedChanged(object sender, EventArgs e)
{
Checkbox cb = sender as CheckBox;
string yourID = cb.Attributes["yourID"];
//Do your thing
}

Categories

Resources