How to get GridView checkAll checkbox to not fire the individual checkboxes? - c#

I have a GridView with each row containing a checkbox, and the header of that column is a checkbox with checkAll functionality:
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<input id="chkAll" onclick="javascript:SelectAllCheckboxes(this);" runat="server" type="checkbox" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkSelect" runat="server" ToolTip="Select this order" AutoPostBack="true" OnCheckedChanged="chkSelect_OnCheckedChanged"/>
</ItemTemplate>
</asp:TemplateField>
...More BoundFields
</Columns>
The javascript behind the SelectAllCheckboxes()
function SelectAllCheckboxes(spanChk) {
// Added as ASPX uses SPAN for checkbox
var oItem = spanChk.children;
var theBox = (spanChk.type == "checkbox") ?
spanChk : spanChk.children.item[0];
xState = theBox.checked;
elm = theBox.form.elements;
for (i = 0; i < elm.length; i++)
if (elm[i].type == "checkbox" &&
elm[i].id != theBox.id) {
//elm[i].click();
if (elm[i].checked != xState)
elm[i].click();
//elm[i].checked=xState;
}
}
My GridView basically contains sales (orders) from my website, so dollar amounts. The OnCheckedChanged event adds (if checked) or subtracts (if unchecked) the current row's price from a totalAmount that is displayed on the page.
This all works great except that when I click the checkAll checkbox, all of the OnCheckedChanged events for all of the row check boxes fire and it takes a long time to process it all. Since all that I am doing in the OnCheckedChanged method is summing amounts, is there a way that I can NOT call the events for the individual checkboxes and just make one call to a separate method that will grab all the GridView rows and sum them all at once?

If you consider doing it all on the server in one postback, you could try this:
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="chkAll" runat="server" ToolTip="Select this order" AutoPostBack="true" OnCheckedChanged="chkAll_OnCheckedChanged"/>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkSelect" runat="server" ToolTip="Select this order" AutoPostBack="true" OnCheckedChanged="chkSelect_OnCheckedChanged"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
On the code behind:
protected void chkSelect_OnCheckedChanged(object sender, EventArgs e)
{
//Process checked item
}
protected void chkAll_OnCheckedChanged(object sender, EventArgs e)
{
foreach (GridViewRow item in grdTest.Rows)
{
CheckBox ckb = (CheckBox)item.FindControl("chkSelect");
//This will not call the individual event
ckb.Checked = ((CheckBox)sender).Checked;
//Process checked item
}
}

Related

How to work with DataBinder.Eval in GridView?

I have a GridView contains Lables, I need to show/hide Lables based on data.
Here is my GridView:
<asp:GridView ID="GridView_Profiles" runat="server" CssClass="grid" HorizontalAlign="Center"
OnRowDataBound="GridView_Profiles_OnRowDataBound" CellSpacing="1" GridLines="None"
AutoGenerateColumns="False" Width="90%">
<Columns>
<asp:Label ID="Label_SelectedCount" runat="server">
<span style="width:auto;color:White;background-color:#0c95be;height:auto;margin:0px;font-size:12px;cursor:pointer;padding-left:10px;padding-right:10px;padding-top:5px;padding-bottom:5px;">
<%#Eval("Count") %>
</span>
</asp:Label>
<asp:Label ID="lblNoCount" runat="server" Text="-"></asp:Label>
</Columns>
</asp:GridView>
In the above GridView RowDataBound how should I check for the bounding data using DataBinder.Eval?
Use this to get Label in RowDataBound event with DataBinder.Eval:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// find your label text in gridview with DataBinder.Eval
string count = DataBinder.Eval(e.Row.DataItem, "Count") as string;
// find your label control in gridview
Label lb = (Label)e.Row.FindControl("Label_SelectedCount");
// check condition to show/hide label (you use your own condition)
if(count > 0)
lb.Visible = true;
else
lb.Visible = false;
}
}
Or you can bind GridView with DataBinder.Eval like:
<asp:TemplateField HeaderText="Count"
<ItemTemplate>
<asp:Label ID="Label_SelectedCount" runat="server" >
<%# DataBinder.Eval(Container.DataItem, "Count")%>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
Note: You can also bind data to Label's Text attribute like this Text='<%#Eval("Count") %>'.

Drop down list and gridview color

OK, I got some help earlier this week in highlighting a cell in GridView based on conditions.
Now, I want to add a drop down list to a column status (done or not done). I got it to work, but I don't know how to change the color once the field is updated with new user input.
I tried using the below code to do it, but I'm guessing I need to call the DDL or template?
Any ideas on how to accomplish this?
I still don't have any luck with this. It looks like when the status field is updated via dropdownlist, it doesn't interpret the new data (autopostback is set to true.) Basically, it thinks that the value is still "null". Any ideas?
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataKeyNames="SID" DataSourceID="SqlDataSource2" OnDataBound="GridView2_SelectedIndexChanged" OnSelectedIndexChanged="GridView2_SelectedIndexChanged">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="SID" HeaderText="SID" InsertVisible="False" ReadOnly="True" SortExpression="SID" />
<asp:BoundField DataField="Servers" HeaderText="Servers" SortExpression="Servers" />
<asp:TemplateField HeaderText="Status" SortExpression="Status">
<EditItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server" SelectedValue='<%# Bind("Status") %>' OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
<asp:ListItem>done</asp:ListItem>
<asp:ListItem>not done</asp:ListItem>
<asp:ListItem></asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("Status") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code behind:
protected void GridView2_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (GridViewRow row in GridView2.Rows)
{
if (row.Cells[3].Text == "done")
{
row.BackColor = System.Drawing.Color.LimeGreen;
}
else if (row.Cells[3].Text == "not done")
{
row.BackColor = System.Drawing.Color.Red;
}
}
}
If I am understanding you correctly, you need to handle the SelectedIndexChanged event of the DropDownList, not the GridView. You will then use similar logic to what you already have, but find the GridViewRow based on the DropDownList that changed.
Make sure your DropDownList will handle the SelectedIndexChanged event. Remember that DropDownLists do not automatically cause a post back unless told to.
<asp:DropDownList ID="DropDownList1" runat="server"
SelectedValue='<%# Bind("Status") %>'
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
AutoPostBack="True">
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddl = (DropDownList)sender;
GridViewRow row = (GridViewRow)ddl.NamingContainer;
if(ddl.SelectedItem.Text == "done")
{
row.BackColor = System.Drawing.Color.LimeGreen;
}
else if(ddl.SelectedItem.Text == "not done")
{
row.BackColor = System.Drawing.Color.Red;
}
}

How do I pass the number of rows in GridView as an argument to OnRowCommand call

I am trying to make a button & checkbox display on a GridView dynamically only if there is more than 1 row in the GridView. (The view is results based on a search for users, so the number of rows is dynamic based on the search results)
The purpose of button and checkbox allow me to combine 2 or more user accounts. There is no point showing this button if there is only 1 row in the GridView (its confusing), so I set "Visible" parameter using a function. However, using GridViewID.Rows.Count in this function does not work. (What I figure it is actually the max number of rows displayed from when the call to function is taking place). ie: call from 2nd row of Gridview gives me Row.Count=2. So I am trying to pass a hidden control instead, but it is not working.
Here is my code:
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_RowCommand">
<Columns>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:HiddenField ID="HiddenUserID" runat="server" Visible="false" Value= '<%#Eval("UserID") %>' ></asp:HiddenField>
<asp:HiddenField ID="NumberRowsGridView" runat="server" Visible="false" Value='<%#Bind("NumberRowsGridView") %>'></asp:HiddenField>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="UserName" HeaderText="User Name"/>
<asp:BoundField DataField="Email" HeaderText="Email Address"/>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" Visible='<%# ShowMergeUserButton((String)Eval("UserName"),(String)Eval("Email"),(String)Eval("NumberRowsGridView")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="True" HeaderText="Merging Actions">
<ItemTemplate>
<asp:Button ID="Button3" runat="server" CausesValidation="false" CommandName="MergeIntoUser"
Text="Merge Into This Account" CommandArgument='<%# Container.DataItemIndex + "," + Eval("UserID")%>' Visible='<%# ShowMergeUserButton((String)Eval("UserName"),(String)Eval("Email"),(String)Eval("NumberRowsGridView")) %>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
The code behind function:
protected Boolean ShowMergeUserButton(String Username, String Email, String NumRows)
{
return (Username == Email && Convert.ToInt32(NumRows) > 1);
}
I have created a Hidden field and tried to insert it into the GridView, but my code has a runtime error: (Note, I'm new to ASP :)
protected System.Web.UI.WebControls.HiddenField NumberRowsGridView;
-- in function that populates GridView
-- dt is the data source
GridView1.DataSource = dt;
GridView1.DataBind();
NumberRowsGridView.Value = dt.Count<items>().ToString();
The error I get is:
System.Web.HttpException: DataBinding: 'MyASPPageName+dt' does not contain a property with the name 'NumberRowsGridView'.
So I'm basically doing this completely wrong.
This won't answer your question about how to do it in the markup, but when things get complicated like that, I like to go a simpler route. What you could do instead is hide/show the buttons once the entire GridView is bound.
Add the DataBound event to your GridView.
<asp:GridView ID="GridView1" runat="server"
OnRowCommand="GridView1_RowCommand"
OnDataBound="GridView1_DataBound">
Then in this event, all your rows will have been bound. So if you have more than one row, show the button. If not, hide the button. This should give you an idea.
protected void GridView1_DataBound(object sender, EventArgs e)
{
if (GridView1.Rows.Count > 1)
{
foreach (GridViewRow row in GridView1.Rows)
{
Button Button3 = (Button)row.FindControl("Button3");
Button3.Visible = true;
}
}
}
If you must do it in the markup, Enrique Zavaleta's answer should get you there.
I'm not sure what you are trying to accomplish, but this should solve your problem:
Add a property like this in your code, the ViewState will keep your value through the life-cycle of the page.
public string NumberRowsGridView
{
get { return ViewState["NumberRowsGridView"] == null ? null : ViewState["NumberRowsGridView"].ToString(); }
set { ViewState["NumberRowsGridView"] = value; }
}
now edit this part of your code like this
NumberRowsGridView = dt.Count<items>().ToString();
GridView1.DataSource = dt;
GridView1.DataBind();
and the button markup like this
<asp:Button ID="Button3" runat="server" ... Visible='<%# ShowMergeUserButton((String)Eval("UserName"),(String)Eval("Email"), NumberRowsGridView) %>'/>
it should work properly
Since OnRowCommand is an event you can get that information from your event handler. In your codebehind find the GridView1_RowCommand event handler and cast the object sender to GridView like this...
void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
GridView gridView = (GridView)sender;
int numOfRows = gridView.Rows.Count;
// Now you can do something with numOfRows!
}
As far as the other things you are wanting to do, you may want to create a new question that is more specific to those other tasks. But there is no need to pass the number of rows to the event handlers of a GridView because the sender object(the GridView that fired the event) will have all these properties. Hope this helps.

Grid View Row Command Event Not Working

I am having GridView control inside Wizard control, and I am having a linkbutton inside grid, clicking on which will change active index of wizard.
I have three GridViewControls and I am using same Event for RowCommand of these Grids, but its not working, I tried applying breakpoint but its not hitting the break point.
This is my code
w ID="GVUsers" runat="server" OnRowDataBound="GVUsers_RowDataBound" OnRowCommand="GVUsers_RowCommand"
OnRowDeleting="GVUsers_RowDeleting" AutoGenerateColumns="false" CssClass="table">
<Columns>
<asp:TemplateField HeaderText="Crimes" ItemStyle-HorizontalAlign="Left">
<ItemTemplate>
<asp:Label ID="Username" runat="server" Text='<%#DataBinder.Eval(Container.DataItem, "Username") %>'></asp:Label>
<asp:Label ID="gender" runat="server" Text='<%#DataBinder.Eval(Container.DataItem, "Gender") %>'></asp:Label>
<asp:Panel ID="divmsg" runat="server">
<asp:LinkButton
ID="btnlnkpg18" runat="server" Text="Click here" CommandName="pg18"></asp:LinkButton>
</asp:Panel>
</ItemTemplate>
<asp:TemplateField>
<asp:TemplateField HeaderText="Delete" ItemStyle-HorizontalAlign="Left">
<ItemTemplate>
<asp:LinkButton ID="delbtn" runat="server" Text="Delete" OnClientClick="return confirm('Do you really want to delete?');"
CommandName="delete" CommandArgument='<%#DataBinder.Eval(Container.DataItem, "UserId") %>'
CssClass="DeleteBtn"></asp:LinkButton>
</ItemTemplate>
<asp:TemplateField>
</Columns>
</asp:GridView>
protected void GVUsers_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRow row = ((DataRowView)e.Row.DataItem).Row;
var lblgender= e.Row.FindControl("gender") as Label;
var divlnk=e.Row.FindControl("divmsg") as Panel;
if(lblgender.Text=="M")
divlink.Visible=true;
else
divlink.Visible=false;
}
}
protected void GVUsers_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "delete")
{
//Delete
}
if (e.CommandName == "pg18")
{
Wizard1.ActiveStepIndex = 16;
}
}
I also tried setting CommandName in RowDataBound but no luck, Also the Delete Button is not working.
I am databinding GridView like this
if(!Page.IsPostBack)
{
//Bind GridView
}
Syed, try doing this:
1) Rename your RowDataBound event to this:
protected void temp()
2) Go to the aspx page and delete the RowDataBound property from the gridview.
3) With the gridview still highlighted, click design view.
4) In properties click on 'Events' (the lightning bolt).
4) Double click inside the box for RowDatabound to create the event handler in the .cs
5) With in the RowDatabound inside the .cs add a reference to temp();
6) Add a breakpoint just about the temp() within RowDatabound and run your code.
See if it hits the code, if it does then copy everything from test into the RowDataBound.

Find header value for a cell in a grid

I have gridview, I want to do a foreach on it's rows and get the value from column's header where there's a Label for one cell from this row.
foreach (GridViewRow mainRow in grid1.Rows)
{
var header = mainRow.Cells[2].Parent.FindControl("LabelID");//is null
}
How do I find it ?
If you want the value in RowDataBound event then you can check RowType like this
if(e.Row.RowType == DataControlRowType.Header)
{
Label header = (Label)e.Row.FindControl("LabelID");
}
I would access the headerRow and enumerate through the according cells (on buttonClick or on RowDataBound ...)
default.aspx
<asp:GridView AutoGenerateColumns="false" ID="GridView1" runat="server">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:Label ID="headerLabel1" runat="server" Text="Headercolumn1"></asp:Label>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="itemLabel1" runat="server" Text='<%# Eval("name") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="btnGetHeader" runat="server" Text="GetHeader" OnClick="btnGetHeader_Click" />
default.aspx.cs
protected void btnGetHeader_Click(object sender, EventArgs e)
{
foreach (TableCell headerCell in GridView1.HeaderRow.Cells)
{
// or access Controls with index
// headerCell.Controls[INDEX]
Label lblHeader = headerCell.FindControl("headerLabel1") as Label;
if (lblHeader != null)
Debug.WriteLine("lblHeader: " + lblHeader.Text);
}
}

Categories

Resources