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

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 + ".";
}
}

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.

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;
}
}
}

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

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