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>
Related
I want to show an up/down arrow on the header on my sorting gridview. I have implemented it in the code attached below, but on the row data bound event, sortexpression is coming up empty. Because of this, I can't set the image for sorting direction.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
CssClass="gridview_alter" GridLines="Both"
Caption="Submissions today" CaptionAlign="Top"
AllowSorting="true"
AllowPaging="true" PageSize="10" OnPageIndexChanging="GridView1_PageIndexChanging"
OnRowCommand="GridView1_RowCommand" OnRowDataBound="GridView1_RowDataBound"
OnSorting="GridView1_Sorting">
<Columns>
<asp:BoundField DataField="student_name" HeaderText="student_name"
ReadOnly="True" SortExpression="student_name"> </asp:BoundField>
<asp:BoundField DataField="Role" HeaderText="Role"
ReadOnly="True" SortExpression="Role"> </asp:BoundField>
</Columns>
</asp:GridView>
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
string imgAsc = #" <img src='~/images/up.png' border='1' title='Ascending' 'width='50' height='50' />";
string imgDes = #" <img src='~/images/dwn.png' border='1' title='Descendng' 'width='50' height='50' />";
if (e.Row.RowType == DataControlRowType.Header)
{
foreach (TableCell td in e.Row.Cells)
{
LinkButton lnkbtn = (LinkButton)td.Controls[0];
if (lnkbtn.Text == GridView1.SortExpression)//sortexpression is grtting empty here
{
if (GridView1.SortDirection == SortDirection.Ascending)
{
lnkbtn.Text += imgAsc;
}
else
lnkbtn.Text += imgDes;
}
}
}
The best place to check for sortexpression (and any work to do based on sorting) will be the Gridview's OnSorting Event.
So, in this OnSorting event you can get the Header Row and apply the ASC / DESC image.
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
// Get the header row.
GridViewRow headerRow = GridView1.HeaderRow;
if(headerRow != null)
{
foreach (TableCell td in headerRow.Cells)
{
LinkButton lnkbtn = (LinkButton)td.Controls[0];
if (lnkbtn.Text == e.SortExpression)
{
if (GridView1.SortDirection == SortDirection.Ascending)
{
lnkbtn.Text += imgAsc;
}
else
lnkbtn.Text += imgDes;
}
}
}
}
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.
I have a 2 Gridviews. The first grid has a button that when clicked it will populate a second grid with the data based on the id of the button clicked.
I then have code in the RowDataBound function to show the grid based on the row selected. But the problem is the code is automatically running the RowDataBound before the populate function. So the second grid isn't displaying.
Code for GridView:
<asp:GridView style="width:75%"
ID="gvCVRT"
ShowHeaderWhenEmpty="true"
CssClass="tblResults"
runat="server"
OnRowDataBound="gvCVRT_RowDataBound"
OnSelectedIndexChanged="gridviewParent_SelectedIndexChanged"
DataKeyField="ID"
DataKeyNames="ChecklistID"
AutoGenerateColumns="false"
allowpaging="false"
AlternatingRowStyle-BackColor="#EEEEEE">
<HeaderStyle CssClass="tblResultsHeader" />
<Columns>
<asp:BoundField DataField="ChecklistID" HeaderText="ID" ></asp:BoundField>
<asp:CommandField ShowSelectButton="True" HeaderText="Select" />
<asp:BoundField DataField="ChecklistDate" HeaderText="Checklist Date" dataformatstring="{0:dd/MM/yyyy}"></asp:BoundField>
<asp:BoundField DataField="User" HeaderText="User" ></asp:BoundField>
<asp:BoundField DataField="Note" HeaderText="Note" ></asp:BoundField>
</Columns>
</asp:GridView>
Code behind:
protected void gvCVRT_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
lookupCVRT work = (lookupCVRT)e.Row.DataItem;
GridView gv = sender as GridView;
if (work.ID != null)
{
int index = gv.Columns.HeaderIndex("Select");
if (index > -1)
{
e.Row.Cells[index].Attributes.Add("class", "gvCVRTRow");
e.Row.Cells[index].ToolTip = "Click here to Edit Checklist";
}
}
}
}
Code for select button:
protected void gridviewParent_SelectedIndexChanged(object sender, EventArgs e)
{
List<lookupCVRT> workDetails = lookupCVRT.GetChecklistItemsByChecklistID(Company.Current.CompanyID, ParentID.ToString(), gvCVRT.SelectedDataKey.Value.ToString());
gvCVRTDetails.DataSource = workDetails;
gvCVRTDetails.DataBind();
FireJavascriptCallback("setArgAndPostBack ();");
}
So the problem is when I click on the Select button in the grid it runs the RowDataBound first then the gridviewParent_SelectedIndexChanged but I need to run gridviewParent_SelectedIndexChanged first. Can I call the RowDataBound function from gridviewParent_SelectedIndexChanged?
Page_Load function:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GetChecklistID = "";
if (ParentID.HasValue)
{
ViewState["ParentID"] = ParentID;
List<lookupCVRT> work = lookupCVRT.GetCVRTItems(Company.Current.CompanyID, ParentID.ToString());
ViewState["CVRT"] = work;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
else
{
if (ViewState["ParentID"] != null)
{
ParentID = (int?)ViewState["ParentID"];
List<lookupCVRT> work = ViewState["CVRT"] as List<lookupCVRT>;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
}
The OnRowDataBound event is only called if the DataBind method for the GridView has been called.
In your specific case, the problem is in Page_Load in the else branch of the Page.IsPostBack condition:
else
{
if (ViewState["ParentID"] != null)
{
ParentID = (int?)ViewState["ParentID"];
List<lookupCVRT> work = ViewState["CVRT"] as List<lookupCVRT>;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
This code is run for each postback. Unless you reset ViewState["ParentID"] somewhere else in your code, on every postback you bind the GridView gvCVRT again. This is the reason that RowDataBound is called. After finishing Page_Load, the page calls the additional event handlers, in your case gridviewParent_SelectedIndexChanged.
In order to solve this problem, you need to change the code in your Page_Load handler so that there are no calls to DataBind for a postback:
// field moved to class level so that you can access this variable instead of a DataRow in gvCVRT
private List<lookupCVRT> work;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GetChecklistID = "";
if (ParentID.HasValue)
{
ViewState["ParentID"] = ParentID;
work = lookupCVRT.GetCVRTItems(Company.Current.CompanyID, ParentID.ToString());
ViewState["CVRT"] = work;
gvCVRT.DataSource = work;
gvCVRT.DataBind();
}
}
else
{
if (ViewState["ParentID"] != null)
{
ParentID = (int?)ViewState["ParentID"];
work = ViewState["CVRT"] as List<lookupCVRT>;
}
}
}
The root cause of your problem is that you need the data in a postback request and that you put these into ViewState["CVRT"] instead of requesting the data anew. In web applications it is pretty common the read the data again for a new request. So you might think about whether you really need to put the data into ViewState or whether you can request them upon a postback from the data source.
Putting the data into ViewState increases the size of the page that is transferred to the client (basically you have the HTML for the GridView and in addition you have the data in ViewState). So requesting them anew would be the better way in most cases.
I don't know why you preferred to use gridviewParent_SelectedIndexChanged then grdParent_RowDataBound ... i have created a simple solution for you .. it could help you ..
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div>
<label>Parent Grid</label>
<asp:GridView ID="grdParent" runat="server" AutoGenerateColumns="false"
DataKeyField="Id" OnRowDataBound="grdParent_RowDataBound" OnRowCommand="grdParent_RowCommand">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:ButtonField CommandName="Details" HeaderText="Select" Text="Hello" ButtonType="Link" />
</Columns>
</asp:GridView>
</div>
<div>
<label>child Grid</label>
<asp:GridView ID="grdChild" runat="server" AutoGenerateColumns="false"
DataKeyNames="ChildId" OnRowDataBound="grdChild_RowDataBound">
<Columns>
<asp:BoundField DataField="Name" />
<asp:BoundField DataField="Roll" />
<asp:ImageField HeaderText="Image" />
</Columns>
</asp:GridView>
</div>
</div>
</form>
</body>
</html>
Codebehind
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<ParentClass> pList = new List<ParentClass>()
{
new ParentClass{Id=5, Name="V"},
new ParentClass{Id=6,Name="VI"},
new ParentClass{Id=7,Name="VII"},
new ParentClass{Id=8,Name="VIII"},
new ParentClass{Id=9,Name="IX"},
new ParentClass{Id=10,Name="X"},
};
grdParent.DataSource = pList;
grdParent.DataBind();
}
}
protected void grdParent_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem == null || e.Row.RowType != DataControlRowType.DataRow)
{
return;
}
ParentClass p = e.Row.DataItem as ParentClass;
var btn = e.Row.Cells[1].Controls[0] as LinkButton;
btn.CommandArgument = p.Id.ToString();
}
protected void grdParent_RowCommand(object sender, GridViewCommandEventArgs e)
{
int parentId = Convert.ToInt32(e.CommandArgument);
var releventStudents = GetRepositary().FindAll(i => i.ParentId == parentId);
grdChild.DataSource = releventStudents;
grdChild.DataBind();
}
protected void grdChild_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem == null || e.Row.RowType != DataControlRowType.DataRow)
{
return;
}
//lookupCVRT work = (lookupCVRT)e.Row.DataItem;
//GridView gv = sender as GridView;
//if (work.ID != null)
//{
// int index = gv.Columns.HeaderIndex("Select");
// if (index > -1)
// {
// e.Row.Cells[index].Attributes.Add("class", "gvCVRTRow");
// e.Row.Cells[index].ToolTip = "Click here to Edit Checklist";
// }
//}
}
private List<ChildClass> GetRepositary()
{
List<ChildClass> allChild = new List<ChildClass>();
Random r = new Random();
for (int i = 0; i < 50; i++)
{
ChildClass c = new ChildClass
{
ChildId = i,
ParentId = r.Next(5, 10),
Name = "Child Name " + i,
Roll = i
};
allChild.Add(c);
}
return allChild;
}
}
public class ParentClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ChildClass
{
public int ParentId { get; set; }
public int ChildId { get; set; }
public int Roll { get; set; }
public string Name { get; set; }
}
Please help me with following, just something weird is going on.
I have a gridview with paging where the first column is filled with checkboxes.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="..." DataKeyNames="EventID" EnableViewState="false"
GridLines="None" AllowSorting="True"
AllowPaging="True" Width="100%"
onpageindexchanging="GridView1_PageIndexChanging"
onprerender="GridView1_PreRender">
<HeaderStyle Wrap="false" />
<Columns>
<asp:TemplateField HeaderStyle-HorizontalAlign="Left">
<HeaderTemplate>
<asp:CheckBox ID="SelectAllEvs" runat="server" EnableViewState="false" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="EventSelector" runat="server" EnableViewState="false" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField ... >
<ItemStyle Wrap="False" />
</asp:BoundField>
<asp:BoundField ... >
</asp:BoundField>
<asp:BoundField ... >
</asp:BoundField>
</Columns>
</asp:GridView>
CodeBehind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["PageIndex"] != null)
{
GridView1.PageIndex = Convert.ToInt32(Session["PageIndex"]);
}
}
}
protected void GridView1_PreRender(object sender, EventArgs e)
{
// loading checkbox values from the session collection
GridView gv = (GridView)sender;
LoadCheckboxState(gv);
Session["PageIndex"] = gv.PageIndex;
}
private void LoadCheckboxState(GridView gv)
{
for (int i = 0; i < gv.Rows.Count; i++)
{
var chkBox = GridView1.Rows[i].FindControl("EventSelector") as CheckBox;
int id = gv.PageIndex * gv.PageSize + i;
if (SelectedIndexes.Contains(id))
{
chkBox.Checked = true;
}
else
{
chkBox.Checked = false;
}
}
}
private List<int> SelectedIndexes
{
get
{
if(Session["selectedRows"] == null)
{
Session["selectedRows"] = new List<int>();
}
return (List<int>)Session["selectedRows"];
}
}
private void SaveCheckboxState(GridView gv)
{
for (int i = 0; i < GridView1.Rows.Count; i++)
{
var chkBox = GridView1.Rows[i].FindControl("EventSelector") as CheckBox;
int id = gv.PageIndex * gv.PageSize + i;
if (chkBox.Checked)
{
//see if we have an id added already
if (!SelectedIndexes.Contains(id))
{
SelectedIndexes.Add(id);
}
}
else
{
if (SelectedIndexes.Contains(id))
{
SelectedIndexes.Remove(id);
}
}
}
}
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
// saving current page checkbox values to the session collection
GridView gv = (GridView)sender;
SaveCheckboxState(gv);
GridView1.PageIndex = e.NewPageIndex;
}
When I first get to my page I check some checkboxes and then press F5. Apparently after pressing it I dont have any values in SelectediIndexes and all unselected checkboxes must be checked = false on the PreRender stage but they appear checked after all this. And the problem of the same nature: I checked some on the first page; went to the second page (currently having 2 indexes in the SelectedValues) and after pressing F5 the same I have checked the same checkboxes as on the first page, though they mustn't. I'm absolutely confused with this. How can I fix this? Thanx for any help.
I've found the reason to that strange behavior. I'm using Firrefox. And one of the features of this browser is saving state of some fields when refreshing the page. If you want to refresh a page fully you should refresh it with pressed shift button. Tested in Google Chrome - works just fine.
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