I have to load a large amount of data to a dynamic grid view. Grid view having link button created dynamically based on data.
While clicking the link button, Inner Grid should be loaded. It is working fine.
But every time, on clicking the link button, on the Row bound event is fired, to bind the main grid.
With in the row bound event, inner grid is loading for each row in main grid , which is already clicked. i have maintain the clicked link button state(id field of the particular row) in Session, and using the session value , loading the inner grid on each row in main grid which is matched the session value in row bound event.
But loading takes long time. Is any other way to binding data to dynamic grid view on clicking the link button and maintain the clicked link button inner grid ?
My code is
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (strCallTypeName[intLoop].ToLower() != "total")
{
LinkButton lnk = new LinkButton();
lnk.Text = ((System.Data.DataRowView)(e.Row.DataItem)).Row[strCallTypeName[intLoop]].ToString();
lnk.CommandArgument = strCallTypeName[intLoop]
+ "|||"
+ ((System.Data.DataRowView)(e.Row.DataItem)).Row["UserId"].ToString()
+ "|||"
+ ((System.Data.DataRowView)(e.Row.DataItem)).Row["Service"].ToString()
+ "|||"
+ e.Row.RowIndex;
//lnk.Click += new EventHandler(lnk_Click);
//lnk.CommandName = "Edit";
lnk.Click += new EventHandler(lnk_Click);
lnk.ToolTip = strCallTypeName[intLoop];
lnk.CssClass = "lnk";
tc.Controls.Add(lnk);
string strUserID =grdSummaryCall.DataKeys[e.Row .RowIndex].Value.ToString();
string strSessionUserDetails = string.Empty;
strSessionUserDetails = (string)Session["GridUserDetails"];
if (strSessionUserDetails != string.Empty && strSessionUserDetails !=null)
{
string[] strSplitUserDetails = strSessionUserDetails.Split(new string[] { "~" }, StringSplitOptions.None);
Panel pnlTable = (Panel)e.Row.FindControl("pnlTable");
for (int i = 0; i < strSplitUserDetails.Length; i++)
{
string[] strUserDetails = strSplitUserDetails[i].Split(new string[] { "," }, StringSplitOptions.None);
if (strUserID == strUserDetails[1].ToString())
{
if (pnlTable.Visible == false)
{
GetUserCallDetails(strUserDetails, e.Row);
pnlTable.Visible = true;
}
}
}
}
}
}
Pooja, based on your comment above, I would make sure paging is working as expected and you are:
1 - only loading 30 records at time for the current page, not all of them and rendering
only 30.
2 - NOT calling again the database layer for each row binding; You can load all details for every single row of the page at once (so no more than page size, in your case 30), when loading the data for the current page, so your database calls would go down to 1 per page not 1 + pagesize == 31 in your case.
Related
As stated in the title, I have noticed some weird behaviour with my Data Grid View control. The cell click event is supposed to load details from the rows into textboxes and datepicker controls. This works for some rows of the data grid view but other rows are outright ignored.
The code:
`
private void dataGridViewAdmin_CellClick(object sender, DataGridViewCellEventArgs e)//Textbox and datepicker field input automation
{
if (e.RowIndex == -1)
{
return;
}
//Automatically fills the text fields with the User's selection.
DataGridViewRow selectedRow = dataGridViewAdmin.Rows[e.RowIndex];
txtName_Field.Text = selectedRow.Cells[1].Value.ToString();
txtPhone_Field.Text = selectedRow.Cells[5].Value.ToString();
try
{
dataGridViewAdmin.Rows[e.RowIndex].Selected = true;
datepickerEnd.MaxDate = (Convert.ToDateTime(selectedRow.Cells[4].Value)).AddDays(+7);
datepickerEnd.MinDate = (Convert.ToDateTime(selectedRow.Cells[3].Value)).AddDays(+1);
datepickerStart.Value = Convert.ToDateTime(selectedRow.Cells[3].Value);
datepickerEnd.Value = Convert.ToDateTime(selectedRow.Cells[4].Value);
Booking_ID = Convert.ToInt32(selectedRow.Cells[7].Value);
lblID.Text = "Selected ID: " + Booking_ID;
lblID.Visible = true;
}
catch (ArgumentOutOfRangeException) //Catches exception thrown if user from rows of data that have values that are more than seven days apart.
{
if(datepickerEnd.MaxDate < datepickerEnd.MinDate)
{
datepickerEnd.MaxDate = datepickerEnd.MinDate.AddDays(+7);
}
}
`
I've set a breakpoint within the code to see if it breaks on cell click. It breaks for some cells and does nothing on others. Naturally, I've tried spamming the mouse in on the problem cells to no effect.
I've tried to sort the rows differently, still no change.
Your help with this question will be appreciated.
I have created multiple linkbutton on same cell of gridview row. But it's click event is not firing. On click event, I have to get StudentID defined in RowDataBound of Gridview.
protected void gvStudent_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//loop through the cell.
for (int j = 1; j < e.Row.Cells.Count; j++)
{
string[] arrLinks = null;
if (!string.IsNullOrEmpty(e.Row.Cells[j].Text.ToString()) && e.Row.Cells[j].Text.ToString() != " ")
{
arrLinks = e.Row.Cells[j].Text.Split(',');//Rahul-3495,Meera-2323
}
if (arrLinks != null)
{
for (int i = 0; i < arrLinks.Length; i++)
{
LinkButton btnLink = new LinkButton();
string StudentName= (arrLinks[i].Split('-').First()).ToString();//Rahul
string StudentID = (arrLinks[i].Split('-').Last()).ToString();//3495
btnLink.ID ="btn_" + StudentID;
btnLink.Text = StudentName + "<br>";
// btnLink.Click += new EventHandler(StudentButtonsclick);
btnLink.CommandName = "btnLink";
e.Row.Cells[j].Controls.Add(btnLink);
}
}
}
}
}
protected void gvStudent_RowCommand(sender s, GridViewCommandEventArgs e)
{
if (e.CommandName == "btnLink")
{ }
}
<asp:GridView ID="gvStudent" runat="server" AutoGenerateColumns="true"
CssClass="gridview_alter"
OnRowDataBound="gvStudent_RowDataBound" OnRowCommand="gvStudent_RowCommand">
</asp:GridView>
Ok, the problem is that controls that require events that are created "after" the page has been rendered cannot really be wired up. You would have to move the code to a earlier event. So you are free to add controls, but they will in "most" cases be rendered TOO LATE to have events attached. Thus when you click on the link button, nothing fires.
So there are two solutions I can think of that will work.
First, set the control to have a a post back URL, and include a parameter on that post back.
eg this:
Dim lnkBtn As New LinkButton
lnkBtn.Text = "<br/>L" & I
lnkBtn.ID = "cL" & I
lnkBtn.PostBackUrl = "~/GridTest.aspx?r=" & bv.RowIndex
If you put a PostbackUrl, then when you click on the button, the page will post back. However, the grid row events such as rowindex change, or row click event etc. will NOT fire. So, if you willing to have a parameter passed back to the same page as per above, then you can pass the 1-3 (or 1-N) values you have for each control.
Of course that means you now have a parameter on the web page URL (and users will see this). You of course simply pick up the parameter value on page load with the standard
Request.QueryString["ID"] or whatever.
However, another way - which I think is better is to simple wire up a OnClickClick() event in js, and thus do this:
I = 1 to N
Dim lnkBtn As New LinkButton
lnkBtn.Text = "<br/>L" & I
lnkBtn.ID = "cL" & I
lnkBtn.OnClientClick = "mycellclick(" & I & ");return false;"
Now in above note how I am passing "I" to the js routine. You would pass your 200, 300 or whatever value you want.
then you script will look like this:
<script>
function mycellclick(e) {
__doPostBack("MySelect", e);
}
</script>
So above simply takes the value passed from the cell click (and linkbutn), and then does the postback with a dopostback. I used "MySelect", and you can give that any name you want.
Now, in the on-load event, you can simply go like this:
If Request("__EVENTTARGET") = "MySelect" Then
Dim mypassvalue As String = Request("__EVENTARGUMENT").ToString
Debug.Print("row sel for MySelect = " & mypassvalue)
End If
So, you are 100% correct - clicking on those controls does NOT fire server side event, and they are wired up too late for this to occur. so you can and often do say add some columns or controls to a gridview, but they are created and rendered TOO LATE for the events to be wired up (and thus they don't fire when clicked on).
But, you can add a postback to the lnkbutton, and you can also add a OnClickClick() event (JavaScript function call) and they will both work. I don't like parameters in the URL appearing when you click, so I think the js script call as per above works rather nice.
So while in the comments I noted (and suggested) that you have to set the CommandName="Select". This suggesting still holds true (without CommandName = select, then the rowindex will not fire. You can't use just ANY name - it MUST be select. However this ONLY works if the control is part of the grid and not added on the fly. As noted, it might be possible to move the grid event to "earlier" event (page initialize) but it going to be a challenge and will require you to re-organize the page. The most clean, and one that does not require parameters in the URL is adding that js OnClientClick() event. You can however set the controls postbackurl and along with a parameter in the URL, and that also can work well if you open to URL with parameters (I don't like them).
I would recommend using CommandName and OnRowCommand event for GridView. Here is how you should do it:
protected void gvStudent_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//loop through the cell.
for (int j = 1; j < e.Row.Cells.Count; j++)
{
string[] arrLinks = null;
if (!string.IsNullOrEmpty(e.Row.Cells[j].Text.ToString()) && e.Row.Cells[j].Text.ToString() != " ")
{
arrLinks = e.Row.Cells[j].Text.Split(',');//Rahul-3495,Meera-2323
}
if (arrLinks != null)
{
for (int i = 0; i < arrLinks.Length; i++)
{
LinkButton btnLink = new LinkButton();
string StudentName= (arrLinks[i].Split('-').First()).ToString();//Rahul
string StudentID = (arrLinks[i].Split('-').Last()).ToString();//3495
btnLink.ID = "btn_" + StudentID; // Good to concatenate a string instead just a number in the ID.
btnLink.Text = StudentName + "<br>";
btnLink.CommandName = "btnLink"; // Add a CommandName
e.Row.Cells[j].Controls.Add(btnLink);
}
}
}
}
}
protected void GridView1_RowCommand(sender s, GridViewCommandEventArgs e)
{
if (e.CommandName == "btnLink")
{
// Link Button was clicked.
var linkButton = (LinkButton)sender;
if (linkButton != null)
{
var studentId = linkButton.ID.Replace("btn_", ""); // Remove the concatenated string from the id.
// Do stuff with the student id.
// I would highly not recommend getting the id from a button element, as it could be modified using browser inspect elements. Instead use, GridView DataKeys.
}
}
}
You should add RowCommand event in your GridView as well to get it going. e.g:
<asp:GridView runat="server" ID="GridView1" OnRowCommand="GridView1_RowCommand">
<!-- Rest of the elements -->
</asp:GridView>
I have a gridview and on some condition basis, I am inserting text box in it in RowDataBound:
private void GetColumnWithValidation(GridViewRowEventArgs e, string columnName, int columnLength)
{
if (Convert.ToString(DataBinder.Eval(e.Row.DataItem, columnName)).Length > columnLength)
{
int colindex = GetColumnIndexByName(e.Row, columnName);
TextBox txt = new TextBox();
txt.Text = Convert.ToString(DataBinder.Eval(e.Row.DataItem, columnName));
txt.BorderColor = Color.Red;
txt.ID = "txt_" + i + "_" + colindex;
lstErrorTracker.Add(i + "_" + colindex);
//link.NavigateUrl = Convert.ToString(DataBinder.Eval(e.Row.DataItem, "PV_INVOICE_LOCATION"));
e.Row.Cells[GetColumnIndexByName(e.Row, columnName)].Controls.Add(txt);
}
}
Now if I change some data in text box of gridview I want that to be fetch whenever I click Update button. Update button is placed outside of gridview as a normal asp.net button.
But when I am trying to fetch the data I am getting null.
foreach (GridViewRow row in GVUploadDetails.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
TextBox txt= (row.Cells[3].FindControl("txt_0_3") as TextBox);
var test = txt.Text;
}
}
I am getting text data as null. Please help how to get those values. And on other hand I want the entire data of the gridview as a Dataset or datatable how can I get that.
The NamingContainer is the GridViewRow not the cell, so you should use:
foreach (GridViewRow row in GVUploadDetails.Rows)
{
TextBox txt = row.FindControl("txt_0_3") as TextBox;
// ...
}
If this doesn't fix the issue, where in the page's life-cycle do you addd this TextBox programatically? You know that you always have to re-create it on every consecutive postback? Do that latest in Page_Load, better Page_Init.
If you add it from RowDataBound you have to re-create it in RowCreated, otherwise it's too late to retain the ViewState.
I am getting this error
"Failed to load viewstate. The control tree into which viewstate is
being loaded must match the control tree that was used to save
viewstate during the previous request. For example, when adding
controls dynamically, the controls added during a post-back must match
the type and position of the controls added during the initial
request. "
when I try to submit a page where I applied some logic on GridView rowdatabound to alter the RowSpan. On commenting this event there is no error.
here is the code :
int firstRow;
string previousCat;
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var drv = e.Row.DataItem as QCParameters;
if (previousCat == drv.AuditTypeValue)
{
//If it's the same category as the previous one
//Increment the rowspan
if (GridView1.Rows[firstRow].Cells[0].RowSpan == 0)
{
GridView1.Rows[firstRow].Cells[0].RowSpan = 2;
GridView1.Rows[firstRow].Cells[5].RowSpan = 2;
}
else
{
GridView1.Rows[firstRow].Cells[0].RowSpan += 1;
GridView1.Rows[firstRow].Cells[5].RowSpan += 1;
}
//Remove the cell
if (e.Row.Cells.Count > 5)
e.Row.Cells.RemoveAt(5);
e.Row.Cells.RemoveAt(0);
}
else //It's a new category
{
e.Row.VerticalAlign = VerticalAlign.Top;
//Maintain the category in memory
previousCat = drv.AuditTypeValue;
firstRow = e.Row.RowIndex;
}
}
}
The problem is that you remove cells and than during postback (when the control tree is recreated) it does not match and the ViewState cant be loaded.
One possible solution would be to "hide" the cells instead by setting: e.Row.Cells[5].Visible = false;
Not Visible controls will not be rendered but will still be part of the page control tree.
My problem
On RowDataBound, I have programmatically added dropdownlists to every cell in a GridView. Each dropdownlist is populated with the same DataSource.
When the program is running, the user will select different items from the dropdownlists, and then press the 'Save' button. At this point, I am meant to retrieve the selecteditem for every dropdownlist in the GridView and save it back to a database.
However, when I attempted to use the FindControl() method on the GridView and find the dropdownlists to get the selecteditems from each of them, there was none to be found. I realised that maybe due to postback the dropdonwlists are getting removed, as they were added programmatically on RowDataBound.
To work around this, I saved the GridView to Cache after adding in the dropdownlists on RowDataBound and then re-populated the gridview again on button click with all the controls etc...
Only then did I realise that obviously because I was repopulating the dropdowns, that any selecteditem chosen at runtime was getting wiped...
My questions
Is there a way to not get rid of all my controls on PostBack?
AND/OR
Is there a way to somehow store all the selecteditems chosen at runtime before the 'Save' button is clicked?
Code for assistance
protected void gv_Rota_RowDataBound(object sender, GridViewRowEventArgs e)
{
for (int i = 1; i <= ColumnCount; i++)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int day = e.Row.RowIndex;
day += 1;
ddlShift = new DropDownList();
ddlShift.ID = "ddlShift" + "WK" + i.ToString() + "DAY" + day.ToString();
ddlShift.DataSource = DCListOfShifts;
ddlShift.DataValueField = "SHIFT_ID";
ddlShift.DataTextField = "SHIFT_NAME";
ddlShift.Attributes.Add("Place", i.ToString());
ddlShift.DataBind();
ddlShift.Items.Insert(0, new ListItem("Shift..."));
ddlShift.CssClass = "ddl_rotamanager";
e.Row.Cells[i].Controls.Add(ddlShift);
}
}
Cache.Add("cacheGridView", gv_Rota, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 60, 0), CacheItemPriority.Default, null);
}