Why does GridView not render the header row as thead after postback? - asp.net

Setting TableSection = TableRowSection.TableHeader after the grid is bound works initially, putting the header row in thead. After a postback (where the grid is not re-bound) the header row reverts to the table body. I expect the header row to stay in thead; can someone explain why this is not the case or what I am doing wrong?
Sample:
Click the button to cause a postback. The header is not orange after the postback since it's not in thead anymore.
aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="gridtest.aspx.cs" Inherits="ffff.gridtest" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<style type="text/css">
thead th { background-color:Orange;}
</style>
</head>
<body>
<form id="form1" runat="server">
<div><asp:Button ID="Button1" runat="server" Text="Button" />
this button is here just to trigger a postback</div>
<asp:GridView ID="gv1" runat="server"></asp:GridView>
</form>
</body>
</html>
code
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ffff
{
public partial class gridtest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
gv1.DataBound += new EventHandler(gv1_DataBound);
if (!IsPostBack) { BindGrid(); }
}
void Page_PreRender(object sender, EventArgs e)
{
if (gv1.HeaderRow != null)
System.Diagnostics.Debug.WriteLine(gv1.HeaderRow.TableSection); // still TableHeader after postback
}
void gv1_DataBound(object sender, EventArgs e)
{
if (gv1.HeaderRow != null)
{
gv1.HeaderRow.TableSection = TableRowSection.TableHeader;
}
}
private void BindGrid()
{
gv1.DataSource = this.Page.Controls;
gv1.DataBind();
}
}
}

Use the Pre_Render_Complete event instead to add the table section. This will ensure the thead section is always added. As you are currently doing it on DataBound the section will only be added when the data is bound.
protected override void OnPreRenderComplete(EventArgs e)
{
if (gv1.Rows.Count > 0)
{
gv1.HeaderRow.TableSection = TableRowSection.TableHeader;
}
}
Feel free to change the row check I use to checking the Header Row exists as you currently do.

You must set TableSection after DataBind method.
gv1.DataSource = this.Page.Controls;
gv1.DataBind();
gv1.HeaderRow.TableSection = TableRowSection.TableHeader;

Just put the below code in prerender event of gridview
protected void gv_PreRender(object sender, EventArgs e)
{
if (gv.Rows.Count > 0)
{
gv.UseAccessibleHeader = true;
gv.HeaderRow.TableSection = TableRowSection.TableHeader;
}
}

Related

How can I call eventhandler?

void lbl_Click(object sender, EventArgs e)
{
LinkButton lnk = sender as LinkButton;
int currentPage = int.Parse(lnk.Text);
int take = currentPage * 10;
int skip = currentPage == 1 ? 0 : take - 10;
FetchData(take, skip);
}
Hi,
I want to call the method lbl_Click() whenever the click happens.
How can I define any aspx tag to call a function " lbl_Click()" whenever the click happens? or can I use javascript to invoke this "lbl_Click()" function?
Code for Event handler lbl_Click would be executed only when Click Event is fired from the link button. Functionally, this should happen when you click your paging link buttons.
Try to put a breakpoint in lbl_Click function and fire event by clicking on the paging link buttons in UI.
Since, it is still not working for you. I have created a small working page to show you how it should be.
Code Behind
using System;
using System.Web.UI.WebControls;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
CreateDynamicLinkControls();
}
private void CreateDynamicLinkControls()
{
for (int i = 0; i < 10; i++)
{
LinkButton lk = new LinkButton();
lk.Click += new EventHandler(lbl_Click);
lk.ID = "lnkPage" + (i + 1).ToString();
lk.Text = (i + 1).ToString() + " ";
this.form1.Controls.Add(lk);
}
}
void lbl_Click(object sender, EventArgs e)
{
LinkButton lnk = sender as LinkButton;
int currentPage = int.Parse(lnk.Text.Substring(0, 1));
lblLinkText.Text = currentPage.ToString();
}
}
ASPX Page
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
You Clicked : <asp:Label runat="server" ID="lblLinkText"></asp:Label>
</div>
</form>
</body>
</html>
Using this Code
Try to run the page and then link button would appear on the page, label is placed on the page which displays which page was clicked.

Creating dynamic button and its event handler

I am trying to use dynamics buttons and events. When I clicked static button and I showed dynamic button. But When I clicked dynamic button I didn't work dinamikButon_Click event. What is my wrong? Sorry my language. Thx in advance.
Default.aspx.cs is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace TestWebApplication
{
public partial class _Default : Page
{
int i = 1;
Button dinamikButon;
protected void Page_Load( object sender, EventArgs e )
{
}
protected void btnStatik_Click( object sender, EventArgs e )
{
dinamikButon = new Button
{
Text = "Dinamik" + i,
ID = "btnDinamik" + i,
CommandArgument = "commandArgument",
CommandName = "commandName"
};
dinamikButon.Click += dinamikButon_Click;
panel1.Controls.Add( dinamikButon );
i++;
}
void dinamikButon_Click( object sender, EventArgs e )
{
Label1.Text = "Merhaba dinamik butondan geliyorum.";
}
}
}
that's because when the page posts back the button doesn't exist. You have to create the buttons on page Load or PreInit. Microsoft suggests PreInit You can dynamically set a master page or a theme for the requested page, and create dynamic controls.
int i = 1;
Button dinamikButon;
private void Page_PreInit(object sender, EventArgs e)
{
if(Page.IsPostBack)
{
CreateButton();
}
}
protected void btnStatik_Click( object sender, EventArgs e )
{
CreateButton();
}
private void CreateButton()
{
dinamikButon = new Button
{
Text = "Dinamik" + i,
ID = "btnDinamik" + i,
CommandArgument = "commandArgument",
CommandName = "commandName"
};
dinamikButon.Click += dinamikButon_Click;
panel1.Controls.Add( dinamikButon );
i++;
}
Update:
Do do what you've asked now we have to specify that the button has been created using either viewstate, querystring or session.
In this example I'll use a session:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Page.IsPostBack)
{
if (Session["Created"] != null)
{
CreateButton();
}
}
}
private void CreateButton()
{
dinamikButon = new Button
{
Text = "Dinamik" + i,
ID = "btnDinamik" + i,
CommandArgument = "commandArgument",
CommandName = "commandName"
};
Panel1.Controls.Add(dinamikButon);
dinamikButon.Click += dinamikButon_Click;
i++;
Session["Created"] = "true";
}
private void dinamikButon_Click(object sender, EventArgs e)
{
//your action here
}
To fill value in "Label1" control using dynamic button
Default.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DynamicCtrl._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript">
function dynamicevnt() {
document.getElementById("Label1").innerHTML = "Merhaba dinamik butondan geliyorum.";
return false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnStatik" runat="server" Text="Click" OnClick="btnStatik_Click" />
<asp:Label ID="Label1" runat="server"></asp:Label>
<asp:Panel ID="panel1" runat="server">
</asp:Panel>
</div>
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace DynamicCtrl
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnStatik_Click(object sender, EventArgs e)
{
CreateButton();
}
private void CreateButton()
{
int i = 1;
Button dinamikButon = new Button();
dinamikButon.Text = "Dinamik" + i;
dinamikButon.ID = "btnDinamik" + i;
dinamikButon.OnClientClick = "return dynamicevnt();";
dinamikButon.Click += new EventHandler(dinamikButon_Click);
panel1.Controls.Add(dinamikButon);
i++;
}
protected void dinamikButon_Click(object sender, EventArgs e)
{
Label1.Text = "Merhaba dinamik butondan geliyorum.";
}
}
}

Calling method in parent from user control

For some business related reasons I made a wizard navigation user control. Pretty simple: Next/Previous/Finish buttons.
Each of the parent pages that use this nav user control have a SaveData function, which saves the data and does a bunch of other stuff.
When the user clicks Next/Previous/Finish I want to call the parent's SaveData function before redirecting to the other page. How should I do this or can you recommend a better way (code examples if possible please)?
Thanks in advance!
UserControl should not call Parent's function. It is not a good design.
Instead, you want to bubble up the event from UserControl to the Parent page.
Note: my project's namespace is DemoWebForm.
MyUserControl.ascx
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="MyUserControl.ascx.cs"
Inherits="DemoWebForm.MyUserControl" %>
<asp:Button runat="server" ID="NextButton"
OnClick="NextButton_Click" Text="Next" />
<asp:Button runat="server" ID="PreviousButton"
OnClick="PreviousButtonn_Click" Text="Previous" />
<asp:Button runat="server" ID="FinishButton"
OnClick="FinishButton_Click" Text="Finish" />
MyUserControl.ascx.cs
public partial class MyUserControl : System.Web.UI.UserControl
{
public event ClickEventHandler NextClicked;
public event ClickEventHandler PreviousClicked;
public event ClickEventHandler FinishClicked;
protected void NextButton_Click(object sender, EventArgs e)
{
if (NextClicked != null)
{
NextClicked(sender, e);
}
}
protected void PreviousButtonn_Click(object sender, EventArgs e)
{
if (PreviousClicked != null)
{
PreviousClicked(sender, e);
}
}
protected void FinishButton_Click(object sender, EventArgs e)
{
if (FinishClicked != null)
{
FinishClicked(sender, e);
}
}
}
Parent.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Parent.aspx.cs"
Inherits="DemoWebForm.Parent" %>
<%# Register Src="MyUserControl.ascx" TagName="MyUserControl" TagPrefix="uc1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<uc1:MyUserControl ID="MyUserControl1" runat="server"
OnNextClicked="MyUserControl1_NextClicked"
OnPreviousClicked="MyUserControl1_PreviousClicked"
OnFinishClicked="MyUserControl1_FinishClicked" />
<asp:Literal runat="server" ID="MessageLiteral" />
</form>
</body>
</html>
Parent.aspx.cs
public partial class Parent : System.Web.UI.Page
{
protected void MyUserControl1_NextClicked(object sender,EventArgs e)
{
MessageLiteral.Text = "Next button was clicked";
}
protected void MyUserControl1_PreviousClicked(object sender, EventArgs e)
{
MessageLiteral.Text = "Previous button was clicked";
}
protected void MyUserControl1_FinishClicked(object sender, EventArgs e)
{
MessageLiteral.Text = "Finish button was clicked";
}
}
you only need the delegate:
public delegate void ClickEventHandler(object sender, EventArgs e);
public event ClickEventHandler NextClicked;

FindControl for nested controls in UserControl returns null

I have a very weird issue. I have a UserControl that has some controls inside. I want to refer those controls after, in another postback. But when I try to get them the Controls property of my controls returns null.
I'm working on vs2008.
Here is the sample code:
public partial class MyUserControl : System.Web.UI.UserControl, INamingContainer
{
protected void Page_Load(object sender, EventArgs e)
{
foreach (Control control in this.Controls)
{
Response.Write(control.ClientID);
}
}
private void MyTable()
{
Table table = new Table();
TableRow row = new TableRow();
TableCell cell = new TableCell();
CheckBox check = new CheckBox();
check.ID = "theId";
check.Text = "My Check";
check.AutoPostBack = true;
cell.Controls.Add(check);
row.Cells.Add(cell);
check = new CheckBox();
check.ID = "theOther";
check.AutoPostBack = true;
check.Text = "My Other Check";
cell = new TableCell();
cell.Controls.Add(check);
row.Cells.Add(cell);
table.Rows.Add(row);
this.Controls.Add(table);
}
protected override void Render(HtmlTextWriter writer)
{
MyTable();
base.Render(writer);
}
}
and the Default.aspx page is something like:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.cs" Inherits="Tester.Default" %>
<%# Register TagPrefix="uc1" TagName="MyControl" Src="~/MyUserControl.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Unbenannte Seite</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:MyControl ID="MyControlInstance" runat="server" />
</div>
</form>
</body>
</html>
I don't know if I'm lost in some part of the ASP.NET life cycle. But this situation is making me crazy. Any help would be very grateful.
Create your child controls (MyTable) in either CreateChildControls or OnInit:
protected override void CreateChildControls()
{
MyTable();
base.CreateChildControls();
}
Or
protected override void OnInit(object sender, EventArgs e)
{
MyTable();
base.OnInit(e);
}
You shouldn't/cannot create controls in Render as it occurs after Page_Load. See the ASP.Net Page Lifecycle here.
I believe it is because the Render event occurs after Page_Load, so when you are trying to iterate your control collection, it hasn't been set up yet. Most common solution is to override CreateChildControls to get the proper timing down.

Programmatically insert a TextBox control into GridView.FooterRow

You can modify the columns and the ItemTemplate of columns in a GridView's HeaderRow. But the same is not possible on the FooterRow since it's read-only.
Is there any way that I can programmatically add a TextBox control to a FooterRow in a GridView control?
Note: I don't need databinding on the controls I add.
I may be missing something but can't you hook into the RowDataBound event and add your controls like this?
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Footer)
{
TextBox textBox = new TextBox();
textBox.Text = "Hello";
e.Row.Cells[0].Controls.Add(textBox);
}
}
Yes I have tried this myself and it works fine, here's the full code...
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" OnRowDataBound="GridView1_RowDataBound"
ShowFooter="True">
</asp:GridView>
</div>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<string> animals = new List<string>();
animals.Add("Cat");
animals.Add("Dog");
animals.Add("Horse");
GridView1.DataSource = animals;
GridView1.DataBind();
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType != DataControlRowType.Footer) return;
TextBox textBox = new TextBox();
e.Row.Cells[0].Controls.Add(textBox);
}
}
Try adding controls to gridview in the gridview_RowCreated event
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{`enter code here`
if (e.Row.RowType == DataControlRowType.Footer)
{
TextBox txt = new TextBox();
txt.ID = "txt_Name";
e.Row.Cells[0].Controls.Add(txt);
}

Resources