Row count of nested GridView is always zero - c#

Parent grid-view is gvAgreement.
Child grid-view is gvProducts.
Code used :
protected void gvAgreement_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string AgreementId = gvAgreement.DataKeys[e.Row.RowIndex].Value.ToString();
GridView gvProducts = e.Row.FindControl("gvProducts") as GridView;
gvProducts.DataSource = GetData(string.Format("SELECT dbo.Agreement.*, dbo.Agreementlist.*, dbo.Store.*, dbo.Agreementlist.Agreement_ID AS agreid FROM dbo.Agreement INNER JOIN dbo.Agreementlist ON dbo.Agreement.Agreement_ID = dbo.Agreementlist.Agreement_ID INNER JOIN dbo.Store ON dbo.Agreementlist.ProID = dbo.Store.Pro_ID WHERE (dbo.Agreementlist.Agreement_ID = '{0}')", AgreementId));
gvProducts.DataBind();
int count = gvProducts.Rows.Count;
Session["countgrid"] = count;
}
}
protected void gvProducts_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (Convert.ToInt32(Session["countgrid"].ToString()) == 1)
{
string message = "alert('Agreement at least must have one product');";
ScriptManager.RegisterClientScriptBlock(sender as Control, this.GetType(), "alert", message, true);
}
}
I tried to define count as global value but it also gives zero.

When / how do you databind the child grid? You should do it inside the OnRowDataBound event of the master grid as, presumably, its contents rely on the row of the master grid in which it is located.
protected void gvAgreement_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string AgreementId = gvAgreement.DataKeys[e.Row.RowIndex].Value.ToString();
GridView gvProducts = e.Row.FindControl("gvProducts") as GridView;
if(gvProducts != null)
{
gvProducts.DataSource = [some query or data source here]
gvProducts.DataBind();
}
int count = gvProducts.Rows.Count;
Session["countgrid"] = count;
}
}
EDITED AFTER COMMENTS
You shouldn't store the row count in a session variable. You don't need to, because the place where you want to make use of it (in the RowCommand event), you can actually find out what it is.
Something like:
protected void gvProducts_RowCommand(object sender, GridViewCommandEventArgs e)
{
var gvProducts = e.Row.FindControl("gvProducts") as GridView;
if (gvProducts != null && gvProducts.Rows.Count < 1)
{
string message = "alert('Agreement must have at least one product');";
ScriptManager.RegisterClientScriptBlock(sender as Control, this.GetType(), "alert", message, true);
}

Related

Adding second class to gridview row in RowDataBound

I wish to add an additional class to a GridView programatically. I know I can do this using the following code:
public void RowDataBound(object sender, GridViewRowEventArgs e)
{
DataRow row = ((DataRowView)e.Row.DataItem).Row;
if (!row.Field<Boolean>("IsActive"))
{
e.Row.Attributes["class"] += "InActive";
}
}
and it works fine. The class "IsActive" is added, however, on alternating rows I end up with this HTML:
<tr class="gvAlternatingStyle" class="InActive"
onmouseover="gvMouseOver(this)"
onmouseout="gvMouseOut(this)" style="cursor:pointer;">
Two class definitions is not what I want. I would prefer to have something like this:
<tr class="gvAlternatingStyle InActive"
onmouseover="gvMouseOver(this)"
onmouseout="gvMouseOut(this)" style="cursor:pointer;">
which is, of course, more valid.
I cannot seem to figure out where/how to adjust this html. Possibly in OnPreRender() but I don't see where. Can anyone give me a pointer?
You could take care of the AlternatingRowStyle-CssClass yourself and add the extra class when needed. You will need to remove it from the GridView header of course.
string AlternatingRowStyleCssClass;
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//check if the row is a datarow
if (e.Row.RowType == DataControlRowType.DataRow)
{
string myClass = string.Empty;
//get the AlternatingRowStyle-CssClass for reference into a variable and delete from the gridview itself
if (e.Row.RowIndex == 0)
{
AlternatingRowStyleCssClass = GridView1.AlternatingRowStyle.CssClass;
GridView1.AlternatingRowStyle.CssClass = "";
}
//check if the row is alternate, if so set the alternating class
if (e.Row.RowIndex % 2 == 1)
{
myClass = AlternatingRowStyleCssClass;
}
//check if you need to add the extra class
DataRow row = ((DataRowView)e.Row.DataItem).Row;
if (!row.Field<Boolean>("IsActive"))
{
myClass += " Inactive";
}
//add all the classes to the row
e.Row.Attributes["class"] = myClass.Trim();
}
//add the class to the gridview again (maybe relevant for postback)
if (e.Row.RowType == DataControlRowType.Footer)
{
GridView1.AlternatingRowStyle.CssClass = AlternatingRowStyleCssClass;
}
}
After muddling with this a while and with help from VDWWD I worked out how to accomplish this with a combination of the above and OnPreRender():
public void RowDataBound(object sender, GridViewRowEventArgs e)
{
DataRow row = ((DataRowView)e.Row.DataItem).Row;
if (!row.Field<Boolean>("IsActive")) {
e.Row.Attributes["class"] += "InActive";
}
protected void PreRender(object sender, EventArgs e)
{
foreach(GridViewRow row in GridView1.Rows)
{
if ((row.Attributes["class"] == "InActive")&&
(row.RowState == DataControlRowState.Alternate)){
row.RowState = DataControlRowState.Normal;
row.Attributes["class"] = "gvAlternatingStyle InActive";
}
}
}

how to prevent dynamically added textbox in gridview to get dispose after postback

I am able to add unlimited textbox column in a row of gridview. but after postback these textboxes get disposed. So how to retain these textboxes and their values after postback?
Code:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
int i = 3;
if (e.Row.RowType == DataControlRowType.DataRow)
{
crcl = (List<string>)ViewState["bdi2"];
foreach(string a in crcl)
{
TextBox TextBox101 = new TextBox();
TextBox101.ID=a;
TextBox101.Width = 60;
TextBox101.Text = (e.Row.DataItem as DataRowView).Row[a].ToString();
e.Row.Cells[i].Controls.Add(TextBox101);
//TextBox101.AutoPostBack = true;
i++;
}
}
}
I hope that this link is useful to you for adding textbox in gridview
http://www.aspforums.net/Threads/201270/Dynamically-add-TextBox-control-to-GridView-Row-in-ASPNet/
And this link too.
http://www.aspsnippets.com/Articles/Adding-Dynamic-Rows-in-ASP.Net-GridView-Control-with-TextBoxes.aspx

How to pass along cell value to row databound event after rowediting event

Below is my code behind:
public void enableEditMedChange(object sender, GridViewEditEventArgs e)
{
MedChangeTable.EditIndex = e.NewEditIndex;
}
protected void MedChangeTable_RowDataBound(object sender, GridViewRowEventArgs e)
{
using (DeveloprodDataClassDataContext adminDB = new DeveloprodDataClassDataContext())
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if ((e.Row.RowState & DataControlRowState.Edit) > 0)
{
DropDownList newMedChangeChangeDD = (DropDownList)e.Row.FindControl("NewMedChangeChangeDD");
newMedChangeChangeDD.SelectedValue = ???
}
}
}
}
I would like to set the drop down's selected value to whatever value was in one of the cells in the row who's edit button was clicked on. How can I pass along this value to the row data bound event?
You can get the value like this:
DropDownList newMedChangeChangeDD = (DropDownList)e.Row.FindControl("NewMedChangeChangeDD");
newMedChangeChangeDD.SelectedValue = DataBinder.Eval(e.Row.DataItem, "YourDataFieldName").ToString();
More informations here.

Gridview index out of range when rows are returning

I want to change the CSS styling of the first row in a gridview:
protected void hoursReportGridView_OnRowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
GridViewRow firstRow = hoursReportGridView.Rows[0];
firstRow.CssClass = "firstRow";
}
}
I am getting this error: Index was out of range. Must be non-negative and less than the size of the collection.
In every instance there are multiple rows returned so I don't understand the issue
'
I assume the first row exists in GridView.Rows after RowDataBound. So you can access it afterwards. So i would use DataBound instead. Note that you also set the first row on every row since RowDataBound is triggered for every row in the grid.
protected void hoursReportGridView_DataBound(object sender, EventArgs e)
{
if(this.hoursReportGridView.Rows.Count > 0)
hoursReportGridView.Rows[0].CssClass = "firstRow";
}
Another option is to use GridViewRow.RowIndex
protected void hoursReportGridView_OnRowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if(e.Row.RowIndex == 0)
e.Row.CssClass = "firstRow";
}
}
Try this:
protected void hoursReportGridView_OnRowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex == 0)
{
e.Row.CssClass = "firstRow";
}
}
Why do you want to do that on the databind for every row?
Just do it in Page_Load:
// Run this after any binding calls, obviously
if(hoursReportGridView.Rows.Count > 0)
{
hoursReportGridView.Rows[0].CssClass = "firstRow";
}

How can i find Last row in a gridview on RowDataBound

protected void gridview1_RowDataBound(object sender, GridViewRowEventArgs e)
{
**if (e.Row.RowIndex >= gridview1.PageSize) // ROW FOOTER TOTAL**
{
e.Row.BackColor = System.Drawing.Color.Firebrick;
e.Row.ForeColor = System.Drawing.Color.White;
}
}
This code works sometimes, someone can help me
DM,cheers
You can try to find the last column in the PreRender event
protected void grid_PreRender(object sender, EventArgs e)
{
GridViewRow row = grdAlert.Rows[grdAlert.Rows.Count - 1];
// do stuff with your row
}
If you just need to change the style of the footer you can use
<asp:GridView ID="grid" runat="server" FooterStyle="your style"></asp:GridView>
A grid view doesn't appear to have a row count until it's finished binding each row. So, another thought:
Can you determine the number of rows from the datatable that the gridview is binding to, then store that in a variable for use later?
you can find last row like this
GridViewRow row = GridView1.Rows[GridView1.Rows.Count-1];
or use this
protected void gridview1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
GridView grid = (GridView)sender;
if(e.Row.RowIndex == (grid.Rows.Count - 1))
{
//last row
}
}
}
It seems that you want to detect the footer row in RowDataBound since you have commented //ROW FOOTER TOTAL, you just have to check for the DataControlRowType.Footer:
protected void gridview1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Footer)
{
// here it is
}
}
Otherwise you could compare the RowIndex with the row of the undrlying DataItem:
DataRowView row = (DataRowView)e.Row.DataItem;
if (e.Row.RowIndex == row.DataView.Count - 1) ; // last row
In your page load method set colors as below
protected void Page_Load(object sender, EventArgs e)
{
//code what you currently have ....
// add below code after that
GridViewRow row = GridView1.Rows.Count-1;
row.BackColor = System.Drawing.Color.Firebrick;
row.ForeColor = System.Drawing.Color.White;
}

Categories