One Checkbox to control gridview rows - asp.net

How can I implement the following: I would like to have a checkbox on the top of my gridview. When checkbox is checked should show all the hidden rows from the gridview but when is unchecked should only show the unhide ones.
I only need 1 checkbox at the top(not in the header of the gridview), I found couple of examples but all of the have checkbox as column and then added to the header as well.
What would be the best way to do this?
Thanks in advance.

This is a one way of doing it on the server:
I define the Gridview and Checkbox as follows:
<asp:CheckBox id="cbShowHidden" runat="server" Text="Show Hidden Rows"
Checked="true" oncheckedchanged="cbShowHidden_CheckedChanged" AutoPostBack="true" ></asp:CheckBox>
<br />
<asp:GridView ID="gvTest" AutoGenerateColumns="false" runat="server"
ShowHeader="true" onrowdatabound="gvTest_RowDataBound">
<Columns>
<asp:BoundField DataField="id" HeaderText="id" />
<asp:BoundField DataField="name" HeaderText="name" />
<asp:BoundField DataField="family" HeaderText="family" />
<asp:BoundField DataField="visibility" HeaderText="visibility" />
</Columns>
</asp:GridView>
This is the codebehind:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
PopulateGrid();
}
}
private void PopulateGrid()
{
gvTest.DataSource = Enumerable.Range(0, 3000).Select(i => new { id = i, name = 2 * i, family = "Unknown", visibility = i % 3 == 0 ? "Visible" : "Hidden" });
gvTest.DataBind();
}
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
bool showHidden = cbShowHidden.Checked;
if (e.Row.RowType == DataControlRowType.DataRow)
e.Row.Visible = showHidden || string.Compare(e.Row.Cells[3].Text, "Visible") == 0;
}
protected void cbShowHidden_CheckedChanged(object sender, EventArgs e)
{
PopulateGrid();
}
This can be greatly optimized by doing the hiding on the client with jQuery.

Related

I can't paint the rows of another page in the gridview, asp.net

I can't solve one thing, I want to paint some rows of the GridView depending on a column. I have no problems with this, but when I change the page, I can't get it to paint.
This is how I do the pagination
GridView2.PageIndex = e.NewPageIndex;
loadgrid();
paintpagin(e.NewPageIndex);
So I try to paint it
GridView2.PageIndex = newPageIndex;
foreach (GridViewRow Rowe in GridView2.Rows)
{
CheckBox Rc = (CheckBox)Rowe.FindControl("rdaprobar");
RadioButton Ri = (RadioButton)Rowe.FindControl("rdpendiente");
RadioButton Rd = (RadioButton)Rowe.FindControl("rdCandelar");
if (Rc.Checked == true)
{
GridView2.Rows[Rowe.DataItemIndex].BackColor = ColorTranslator.FromHtml("#bcf5be");
}
}
The even to use for highlights, formatting, etc.?
use the Grid row data bound event.
So, first up, our markup:
<asp:GridView ID="GHotels" runat="server" CssClass="table" AutoGenerateColumns="false"
width="45%" DataKeyNames="ID" OnRowDataBound="GHotels_RowDataBound" AllowPaging="True"
OnPageIndexChanging="GHotels_PageIndexChanging" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField HeaderText="HotelName">
<ItemTemplate>
<asp:Label ID="txtHotel" runat="server" Text='<%# Eval("HotelName") %>' ></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="270" />
</Columns>
<PagerStyle CssClass="GridPager" />
</asp:GridView>
Code to load:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL =
"SELECT * FROM tblHotels WHERE Description is not null ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
DataTable rstData = new DataTable();
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
GHotels.DataSource = rstData;
GHotels.DataBind();
}
}
}
Our pager code (and NOTE YOU HAVE the load of the grid before the pager - chec your code!!!).
protected void GHotels_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GHotels.PageIndex = e.NewPageIndex;
LoadData();
}
Ok, we now have this:
Now, I highlight each hotel if it is active. NOTE very careful, I don't have that column "active" in the GV, but it was/is part of the data source. So, for bonus points, I demonstrate how to get/grab/use columns that you don't render or have in the GV, but in fact is part of the data source.
So, our code to highlight, we have this:
protected void GHotels_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// get binding data source
DataRowView gData = e.Row.DataItem as DataRowView;
if ((bool)gData["Active"]) {
// Label tHotel = e.Row.FindControl("txtHotel") as Label;
// tHotel.BackColor = System.Drawing.Color.LightSteelBlue;
e.Row.Cells[2].BackColor = System.Drawing.Color.LightSteelBlue;
}
}
}
So, we now have this:
So do NOT try and loop each row of the GV - use the row data bound to highlight and format as per above.

Trying to increment an integer on click of checkboxes

I'm having a scope problem (I think) trying to increment an integer.
I have several CheckBoxes, and want to limit users to only choose a maximum of three. So, I want to increment an integer on each checkbox click which I can check against.
My Default.aspx
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="chkRow" runat="server" autopostback="true" OnCheckedChanged="MyCheckBoxes_SelectedIndexChanged"/>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Title" />
<asp:BoundField DataField="Publisher" />
<asp:BoundField DataField="Genre" />
</Columns>
</asp:GridView>
My Default.aspx.cs
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
DataSet ds = new DataSet();
ds.ReadXml(MapPath("App_Data/publications.xml"));
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
private static int mycount = 0;
protected void MyCheckBoxes_SelectedIndexChanged(object sender, EventArgs e)
{
Label1.Text = mycount.ToString();
Increment(mycount);
}
public static void Increment(int mycount)
{
mycount++;
}
}
My Label1 is always displaying 0.
The names overlap inside the method scope of Increment. Remove mycount as parameter in Increment method

modalpopupextender with dropdownlist and update panel issue

I have asp:DetailsView in popup (I use modalpopupextender) and I have dropdownlist inside detailsview with autopostback. DetailView is inside updatepanel. But when I change value of dropdownlist the PageLoad function is called anyway, and dropdown index changes to 0.
<asp:Button ID="FakeClickButton5" runat="server" Text="FakeButton" CssClass="hideButton" />
<asp:Panel ID="PopupPanelDetail" runat="server" CssClass="modalPopup" >
<asp:Panel ID="Panel6" runat="server" >
<asp:UpdatePanel ID="uptblTest" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:DetailsView ID="DetailsViewMain" runat="server" AutoGenerateRows="false"
DataKeyNames="Id" DataSourceID="ObjectDataSourceDetailMain" Height="50px"
onitemcommand="DetailsViewMain_ItemCommand"
oniteminserted="DetailsViewMain_ItemInserted"
Width="250px" >
<Fields>
<asp:BoundField DataField="Id" HeaderText="Id"
InsertVisible="False" ReadOnly="True" SortExpression="Id"
Visible="False" />
<asp:BoundField DataField="name" HeaderText="name"
SortExpression="name" />
<asp:TemplateField HeaderText="Type">
<ItemTemplate>
<asp:DropDownList ID="ddType" runat="server" AutoPostBack="true" OnSelectedIndexChanged="ddType_OnSelectedIndexChanged" onload="ddType_Load">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowEditButton="True" ShowInsertButton="True"
Visible="False" />
</Fields>
<HeaderStyle CssClass="bold" HorizontalAlign="Center"></HeaderStyle>
</asp:DetailsView>
<asp:Panel ID="Panel7" runat="server">
<asp:LinkButton ID="SaveDetailLinkButton" runat="server" CausesValidation="True"
onclick="SaveDetailLinkButton_Click" SkinID="blackButton" ValidationGroup="ServiceValidation">Save</asp:LinkButton>
<asp:LinkButton ID="CancelDetailLinkButton3" runat="server"
onclick="CancelDetailLinkButton3_Click" SkinID="blackButton">Cancel</asp:LinkButton>
</asp:Panel>
<asp:ObjectDataSource ID="ObjectDataSourceDetailMain" runat="server"
InsertMethod="InsertParam"
SelectMethod="GetParamByID"
UpdateMethod="UpdateParam"
TypeName="DatasorceMatch"
DataObjectTypeName="ParamCustom"
OldValuesParameterFormatString="original_{0}"
oninserting="ObjectDataSourceDetailMain_Inserting" >
<SelectParameters>
<asp:ControlParameter ControlID="GridViewParams" Name="Id"
PropertyName="SelectedDataKey.Value" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Panel>
</asp:Panel>
<ajaxToolkit:ModalPopupExtender ID="ModalPopupExtenderDetails" runat="server"
PopupControlID="PopupPanelDetail" TargetControlID="FakeClickButton2"
BackgroundCssClass="modalBackground" />
actually it's strange that dropdownlist reloaded because update panel mode is conditional and I don't update it in code.
Here is my server code:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void DetailsViewMain_ItemCommand(object sender, DetailsViewCommandEventArgs e)
{
if (e.CommandName == "Cancel")
{
DetailsViewMain.Visible = false;
}
}
protected void DetailsViewMain_ItemInserted(object sender, DetailsViewInsertedEventArgs e)
{
GridViewParams.DataBind();
DetailsViewMain.Visible = false;
}
protected void SaveDetailLinkButton_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
GridViewParams.SelectedIndex = -1;
if (DetailsViewMain.CurrentMode == DetailsViewMode.Edit)
{
DetailsViewMain.UpdateItem(true);
}
if (DetailsViewMain.CurrentMode == DetailsViewMode.Insert)
{
DetailsViewMain.InsertItem(true);
}
ModalPopupExtenderDetails.Hide();
GridViewParams.DataBind();
}
else
{
ModalPopupExtenderDetails.Show();
}
}
protected void CancelDetailLinkButton3_Click(object sender, EventArgs e)
{
ModalPopupExtenderDetails.Hide();
GridViewParams.SelectedIndex = -1;
GridViewParams.DataBind();
}
protected void ObjectDataSourceDetailMain_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
//int selectedID_ofType = (int)ViewState[viewState_typeID];
int selectedID_ofType = int.Parse(dropDownList_ddType.SelectedValue);
((ParamCustom)e.InputParameters[0]).typeID = selectedID_ofType;
}
protected void ddType_Load(object sender, EventArgs e)
{
dropDownList_ddType = (DropDownList)sender;
if (DetailsViewMain.CurrentMode == DetailsViewMode.Insert)
{
((DropDownList)sender).Items.Clear();
((DropDownList)sender).Items.Add(new ListItem(#"Choose", (0).ToString()));
foreach (ParamType paramType in DBHelper.sharedInstance().getAllParamTypes())
{
ListItem listItem = new ListItem(paramType.name, paramType.id.ToString());
((DropDownList)sender).Items.Add(listItem);
}
}
}
protected void ddType_OnSelectedIndexChanged(object sender, EventArgs e)
{
//int selectedID_ofType = int.Parse(((DropDownList)sender).SelectedValue);
//ViewState[viewState_typeID] = selectedID_ofType;
}
What I need is just to change values of dropdownlist without page reloading or without popup disappearing and save this value.

CheckBox in GridView firing CheckedChanged event at wrong time

I have a checkbox in my gridview footer with autopostack=true (which should fire a checkedchanged event), and a linkbutton in my itemtemplate (which should fire the gridview rowcommand event).
Everything has been working fine, until I placed the following code in my gridview rowdatabound (or databound) event:
for (int i = 0; i < gridCartRows.Columns.Count - 2; i++)
{
e.Row.Cells.RemoveAt(0);
}
e.Row.Cells[0].ColumnSpan = gridCartRows.Columns.Count - 1;
Now, when I click my linkbutton, the checkbox checkedchanged event is automatically fired, and then the rowcommand event is fired.
Why is the checkedchanged event being fired when it shouldn't, when I add the above code?
Is there a way to get around this?
Edit
Here's a sample, that reproduces my issue:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" ShowFooter="True"
OnRowCommand="GridView1_RowCommand" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Column1">
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Column2">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" Text="Fire Row Command" CommandName="Fire" />
</ItemTemplate>
<FooterTemplate>
Footer
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="true" OnCheckedChanged="CheckBox1_CheckedChanged" />
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Column3">
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code-behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GridView1.DataSource = new int[5];
GridView1.DataBind();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Footer)
{
for (int i = 0; i < GridView1.Columns.Count - 2; i++)
{
e.Row.Cells.RemoveAt(0);
}
e.Row.Cells[0].ColumnSpan = GridView1.Columns.Count - 1;
((CheckBox)e.Row.FindControl("CheckBox1")).Checked = true;
}
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Fire")
{
Response.Write("RowCommand fired.");
}
}
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
Response.Write("CheckBox fired.");
}
Note, I'm setting the CheckBox property to true in the RowDataBound - if I remove this, it works fine. So merging the cells and setting the checkbox property aren't working nicely together.
GridView Control events are stored in viewstate and they can get messed up very easily. Here removing a cell causing to bind different event to link button. Although after postback __EVENTTARGET is LinkButton, wrong method is called and wrong control, event arguments are passed.
I would suggest to hide the cell rather than removing it:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[1].ColumnSpan = GridView1.Columns.Count - 1;
e.Row.Cells[0].Visible = false;
((CheckBox)e.Row.FindControl("CheckBox1")).Checked = true;
}
}
This will serve the purpose.

GridView event raise unexpectedly after postback

Consider this Asp.net page code:
<head runat="server">
<title></title>
<script type="text/javascript">
function showhide(master, detail) {
var src = $(master).children()[0].src;
if (src.endsWith("plus.png"))
src = src.replace('plus.png', 'minus.png');
else
src = src.replace('minus.png', 'plus.png');
$(master).children()[0].src = src;
$(detail).slideToggle("normal");
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/scripts/jquery-1.6.2.min.js" ScriptMode="Release" />
</Scripts>
</asp:ScriptManager>
<div>
<asp:SqlDataSource ID="sqlDsCustomers" runat="server" ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT [Customers].[CustomerID], [Customers].[CompanyName], COUNT([OrderID]) TotalOrders
FROM [Customers] INNER JOIN [Orders] ON [Customers].[CustomerID]=[Orders].[CustomerID]
Group By [Customers].[CustomerID], [Customers].[CompanyName]">
</asp:SqlDataSource>
<asp:GridView Width="100%" AllowPaging="True" ID="gvCustomers" AutoGenerateColumns="False"
DataSourceID="sqlDsCustomers" runat="server" ShowHeader="False" OnRowCreated="gvCustomers_RowCreated">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<div class="group" id='<%#String.Format("customer{0}",Container.DataItemIndex) %>'
onclick='showhide(<%#String.Format("\"#customer{0}\"",Container.DataItemIndex) %>,<%#String.Format("\"#order{0}\"",Container.DataItemIndex) %>)'>
<asp:Image ID="imgCollapsible" CssClass="first" ImageUrl="~/Assets/img/plus.png"
Style="margin-right: 5px;" runat="server" /><span class="header">
<%#Eval("CustomerID")%>
:
<%#Eval("CompanyName")%>
(<%#Eval("TotalOrders")%>Orders) </span>
</div>
<div id='<%#String.Format("order{0}",Container.DataItemIndex) %>' class="order">
<asp:GridView AutoGenerateColumns="false" CssClass="grid" ID="ddd" runat="server"
ShowHeader="true" EnableViewState="false">
<RowStyle CssClass="row" />
<AlternatingRowStyle CssClass="altrow" />
<Columns>
<asp:TemplateField ItemStyle-CssClass="rownum">
<ItemTemplate>
<%# Container.DataItemIndex + 1 %>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Order ID" DataField="OrderID" ItemStyle-Width="80px" />
<asp:BoundField HeaderText="Date Ordered" DataField="OrderDate" DataFormatString="{0:MM/dd/yyyy}"
ItemStyle-Width="100px" />
<asp:BoundField HeaderText="Date Required" DataField="RequiredDate" DataFormatString="{0:MM/dd/yyyy}"
ItemStyle-Width="110px" />
<asp:BoundField HeaderText="Freight" DataField="Freight" DataFormatString="{0:c}"
ItemStyle-Width="50px" ItemStyle-HorizontalAlign="Right" />
<asp:BoundField HeaderText="Date Shipped" DataField="ShippedDate" DataFormatString="{0:MM/dd/yyyy}"
ItemStyle-Width="100px" />
</Columns>
</asp:GridView>
</div>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
</form>
and the code behind:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void gvCustomers_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string custID = ((DataRowView)e.Row.DataItem)["CustomerID"].ToString();
using (DataClassesDataContext dc=new DataClassesDataContext())
{
List<Order> ord = (from o in dc.Orders
where o.CustomerID == custID.Trim()
select o).ToList();
GridView ctrl = e.Row.FindControl("ddd") as GridView;
ctrl.DataSource = ord;
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect("Default.aspx");
}
the problem is when I Click on Button1 to redirect to another page gvCustomers_RowCreated raise and I get Null reference error.Why this event raised after postback?
EDIT 1):
I removed SqlDataSource and bind GridView in the code behind like this:
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (DataClassesDataContext dc=new DataClassesDataContext())
{
var query = dc.ExecuteQuery<clsRetern>("SELECT [Customers].[CustomerID], [Customers].[CompanyName], COUNT([OrderID]) TotalOrders FROM [Customers] INNER JOIN [Orders] ON [Customers].[CustomerID]=[Orders].[CustomerID] Group By [Customers].[CustomerID], [Customers].[CompanyName]").ToList();
List<clsRetern> ret = new List<clsRetern>();
foreach (var item in query)
{
clsRetern r = new clsRetern();
r.CompanyName = item.CompanyName;
r.CustomerID = item.CustomerID;
r.TotalOrders = item.TotalOrders;
ret.Add(r);
}
gvCustomers.DataSource = ret;
gvCustomers.DataBind();
}
}
}
protected void gvCustomers_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string custID = ((clsRetern)e.Row.DataItem).CustomerID.Trim();
using (DataClassesDataContext dc=new DataClassesDataContext())
{
List<Order> ord = (from o in dc.Orders
where o.CustomerID == custID.Trim()
select o).ToList();
GridView ctrl = e.Row.FindControl("ddd") as GridView;
ctrl.DataSource = ord;
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect("Default.aspx",true);
}
}
public class clsRetern
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public int TotalOrders { get; set; }
}
I tried Response.Redirect("Default.aspx"); but the problem still remains.
If you understand ASP.NET page model then this question should not come to you. Every time request goes to ASP.NET page, a new page object is created along with entire control tree and the state is managed using view-state in post-back scenarios. So in your case, whenever post-back happens, a new page and grid-view is created. The data for the gid-view would be persisted in thew view-state and grid would be bound to that data.
The RowCreated event is raised whenever grid row is created regardless of whether DataBind is explicitly called or not. The intent of the event is so that one can tweak with UI (grid-view cells) - e.g. some controls can be pushed into grid-view cells if required. The same should happen regardless of post-back scenario other wise those dynamic controls will not get created. Typically, these controls will restore their state using view-state and your get your grid-view UI (control tree) back as it was in first page cycle.
Thats because even if you fire Response.Redirect, the Page_Load event would still be raised and if your GridView binding code is not inside !IsPostBack, that code will be hit.
Try this.
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
//bind gridview here
}
}
catch (Exception exception)
{
//Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
}
}
Savvy?
Add EnableViewState=False to the page directive to prevent "RowCreated" running on every post back.

Resources