I have a GridView control that uses a datatable for a data source. I have enabled paging on the control, and the GridView shows the number of rows I've specified as the PageSize. However, there is no paging navigation, so I have no way to change the page.
Question: How do I get the paging navigation to show?
GridView definition:
<asp:GridView runat="server" ID="gvResults" CssClass="report" DataKeyNames="LogId" AllowSorting="True" AllowPaging="True" PageSize="5" OnRowDataBound="gvResults_OnRowDataBound" OnPageIndexChanging="gvResults_OnPageIndexChanging"></asp:GridView>
C#:
//...stuff that gets data from database
DataTable dt = oDs.DataSet.Tables[0];
gvResults.DataSource = dt;
gvResults.DataBind();
NOTE: I've verified in debugger that the datatable dt has more than 100 rows
And the OnPageIndexChanging() event, based on the answer to this question, although it didn't work in my case (I'm not sure why it's necessary since the event shouldn't trigger until you attempt to go to the next page, which would require the paging navigation to show in the first place, right?):
protected void gvResults_OnPageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView gv = (GridView)sender;
DataView dv = gv.DataSource as DataView;
if (dv != null)
{
DataTable dt = dv.Table;
gv.DataSource = dt;
}
gv.PageIndex = e.NewPageIndex;
gv.DataBind();
}
Here is what I see:
I expect to see some way to page through the results.
I have also tried adding a PagerSettings to my GridView, like so:
<asp:GridView runat="server" ID="gvResults" CssClass="report" DataKeyNames="LogId" AllowSorting="True" AllowPaging="True" PageSize="5" OnRowDataBound="gvResults_OnRowDataBound" OnPageIndexChanging="gvResults_OnPageIndexChanging">
<PagerSettings Mode="NextPreviousFirstLast" FirstPageText="First" LastPageText="Last" NextPageText="Next" PreviousPageText="Previous" Position="Bottom"></PagerSettings>
</asp:GridView>
Here is what the rendered HTML looks like for that last row. I modified the css during runtime to expand the row so it's clear that the row is empty. There are no paging controls being hidden by css.
After much banging of head and gnashing of teeth, I finally figured this out.
I have another event that operates OnRowDataBound() which formats a particular column to HTML, and this conversion resulted in no paging controls when it operated on the footer row.
The solution was to check that the bound row is a DataRow before doing the conversion.
protected void gvResults_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (!(sender is GridView) || e.Row.RowType != DataControlRowType.DataRow) return;
//do stuff
}
And then happiness ensued:
Related
I am still a novice with asp.net, so I'm sure there are better ways to do some of this...
I want to allow a user to enter a date, and then execute an SQL query against a database to return all records matching that date. I want to display those records, and allow the user to select one for additional processing. It seemed like the DataGrid with a column of Pushbuttons was a good choice. In fact, I've done this before, but it those cases there was no user interaction involved. The page just ran a fixed SQL query. With what I'm doing now, the data is displayed as I want, but the Pushbuttons aren't working...the ItemCommand event doesn't fire.
I've read a lot of threads about the ItemCommand event not firing, but I still can't get this to work. My understanding is that I need to bind the DataGrid while not in a Postback, and I think my code does that. When I debug the Page_Load event, I can see that the code inside if (!IsPostBack){} is running, and the session variables have the expected data.
On the page that hosts the DataGrid, I have a 'Find' button that executes a SQL query against a database. The query uses a date entered into the textbox that is on that page. In the 'Find' button click event, I store the results of the query (a DataTable) in a session variable, then do a Redirect to re-load the page.
Once the page reloads, the session variables contain my expected data and the data is displayed in the DataGrid, along with the Pushbuttons. When I click any of the buttons in the DataGrid, the contents of the DataGrid disappear and the ItemCommand event does not fire.
Here's the definition of the DataGrid (updated to include the button):
<asp:Panel runat="server" ID="pnlSelect" HorizontalAlign="Left" Visible="true" style="margin-top:10px" >
Please select a participant.
<asp:DataGrid runat="server" ID="grdItems" AutoGenerateColumns="true" BorderColor="black" BorderWidth="1" CellPadding="3" style="margin-left:2px; margin-top:6px" OnItemCommand="grdSelect_ItemCommand" >
<Columns>
<asp:ButtonColumn HeaderStyle-HorizontalAlign="Center" ButtonType="PushButton" Text="Select" HeaderText="Select" CommandName="Select" >
<ItemStyle Width="60px" HorizontalAlign="Center"/>
</asp:ButtonColumn>
</Columns>
</asp:DataGrid>
</asp:Panel>
Here's the Page Load code (unneeded code-behind stuff is commented out):
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["y"] != null)
{
txtFind.Text = Session["x"].ToString();
DataTable table = Session["y"] as DataTable;
Session.Remove("x");
Session.Remove("y");
if (table != null)
{
/*
ButtonColumn buttonColumn = new ButtonColumn
{
HeaderText = "Select",
Text = "Select",
CommandName = "Select",
ButtonType = ButtonColumnType.PushButton,
};
grdItems.Columns.Add(buttonColumn);
foreach (DataColumn c in table.Columns)
{
BoundColumn column = new BoundColumn
{
HeaderText = c.Caption,
DataField = c.Caption,
ReadOnly = true
};
grdItems.Columns.Add(column);
}
*/
grdItems.DataSource = table;
grdItems.DataBind();
}
}
}
}
Here's the relevant 'Find' button event code. I can't post the details of the sql query text, but that part does work and the DataTable does contain the expected data:
DataTable table = DatabaseHelper.FindBySQL(sqlText);
if (table != null && table.Rows.Count > 0)
{
Session["x"] = searchtext;
Session["y"] = table;
Response.Redirect(Request.RawUrl, true);
}
And this the ItemCommand event. I place a breakpoint on the first line, and the debugger never hits it.
protected void grdItems_ItemCommand(object source, DataGridCommandEventArgs e)
{
string item = "";
switch (e.CommandName.ToLower())
{
case "select":
item = e.Item.Cells[1].Text.Trim();
//todo: handle the selected data
break;
}
}
Thanks for any thoughts.
Don
I'm trying to take a GridView and get back the data from the row that was clicked. I've tried the code below and when I click the row I get back the selected index but when I look at the actual rows in the GridView they show empty. Not sure what I am missing.
.ASP make my grid.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="True"
CssClass="datatables" Width="100%"
DataSourceID="SqlDataSource1"
GridLines="None" ShowFooter="True" AllowSorting="True"
onrowcreated="GridView1_RowCreated"
onrowdatabound="GridView1_RowDataBound" ShowHeaderWhenEmpty="True"
onrowcommand="GridView1_RowCommand"
onselectedindexchanged="GridView1_SelectedIndexChanged">
<HeaderStyle CssClass="hdrow" />
<RowStyle CssClass="datarow" />
<PagerStyle CssClass="cssPager" />
</asp:GridView>
On each row data bound I make sure that the click should set the selected index.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(GridView1, "Select$" + e.Row.RowIndex);
}
}
Then when the selected index changes by clicking this gets fired which I can put a breakpoint on the first line and I see the index of what I clicked on get stored in a. However when I get to the foreach it skips right past it because it shows GridView1 having a Count of 0 rows. In theory it should have a couple hundred rows and when the index matches it should grab the data in the 6th cell over and store it in string b. Why am I getting no rows on the click?
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
int a = GridView1.SelectedIndex
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowIndex == a)
{
b = row.Cells[6].Text;
}
}
}
Here is my page load.
protected void Page_Load(object sender, EventArgs e)
{
c = HttpContext.Current.Session["c"].ToString();
SqlDataSource1.ConnectionString = //My secret
string strSelect = "SELECT columnnames from tablenames where c in (#c)
SqlDataSource1.SelectParameters.Clear();
SqlDataSource1.SelectCommand = strSelect;
SqlDataSource1.SelectParameters.Add("c", c);
try
{
GridView1.DataBind();
}
catch (Exception e)
{
}
GridView1.AutoGenerateColumns = true;
}
Try just grabbing the row from the SelectedRow property:
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow row = GridView1.SelectedRow;
string b = row.Cells[6].Text;
}
It's my understanding that the Rows collection doesn't get repopulated on PostBacks when you're using those data source controls (like SqlDataSource).
You could probably use your existing code if you called .DataBind() on your GridView prior to trying to iterate through the Rows:
GridView1.DataSourceID="SqlDataSource1";
GridView1.DataBind();
But that seems a little hacky.
After seeing your Page_Load, I see that you need to wrap your databinding code in an if(!Page.IsPostBack) block. Databinding on every postback is interrupting the process of ASP.NET maintaining the state of your controls via the ViewState.
I've gone through several articles and tutorials, but I just can't figure this out. Everything basically says, "oh just turn on AllowPaging, and you're done!" When I do that, yes, I can see the paging controls under the GridView in the Design View, but when I compile, I can't see the page numbers in the running site.
One thing I noticed different from all of the examples, is that I do the data work from the code-behind. Therefore my GridView is simply:
<asp:GridView ID="gvlatest" runat="server" Width="99%" AllowSorting="True"
onrowdatabound="gvlatest_RowDataBound" onsorting="gvlatest_Sorting"
AllowPaging="True" PageSize="2" />
What I mean by doing the data work from behind, is that all the columns and everything, are constructed from code into a DataTable, and then I set the GridView's DataSource to the DataTable. For example, a grossly abbreviated version of what I have:
DataTable temptable = new DataTable();
DataColumn titlecol = new DataColumn();
titlecol.ColumnName = "Title";
temptable.Columns.Add(titlecol);
gvlatest.DataSource = temptable;
gvlatest.DataBind();
This is just a personal preference I guess, and to be honest I've actually never learned how to use the DataSource controls and such that all the examples are using, where you build the GridView in the .aspx file with the columns, data source, etc. So I'm guessing that my problem lies in that general direction...
The question is, what am I doing wrong? Why are the page numbers not showing up? Is setting "AllowPaging" to true really all that I need to do?
For Paging to work, your datasource must support it. If it does not, like a DataTable, then you have to do this yourself.
This code should help.
OnPageIndexChanging="myGridview_PageIndexChanging"
protected void myGridview_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView gv = (GridView)sender;
DataView dv = gv.DataSource as DataView;
DataTable dataTable = dv.Table;
gv.DataSource = myDataTable;
gv.PageIndex = e.NewPageIndex;
gv.DataBind();
}
you have to use the page_index changing event in the gridview to implement paging in the gridview refer this link:
http://forums.asp.net/t/1245611.aspx
hope it helps
You can disable particular column and add Paging
protected void Gridview1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
//----------------------------------Grid view column invisible------------------------------------------------------------
if (Request.QueryString.Get("show") == "all")
GridView1.Columns[0].Visible = true;
else
GridView1.Columns[0].Visible = false;
//-------------------------------------------------------------------------------------------------------------------------
}
protected void Gridview1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
gvbind();// Grid View Binded
}
// Source Code
allowpaging="true" OnPageIndexChanging="Gridview1_PageIndexChanging" pagesize="2"
I have a gridview, grid has 5 different columns ID,FirstName,LastName,DateOfBirth and Age, gridview can be edited, so I want to update the Age depending on DateOfBirth column so I have written the necessary functionality in OnRowBound function.When i execute the grid view page I get "String is not Recognized as valid datetime".
Here is the Function of OnRowBound
protected void UserInfoGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DateTime DOBOnGrid = DateTime.ParseExact(e.Row.Cells[3].Text,"MM/dd/yyyy",null);
Label tAge = (Label)e.Row.Cells[4].FindControl("txtAge");
TimeSpan ts = DateTime.Now - DOBOnGrid;
int CurrAge = ts.Days / 365;
tAge.Text = CurrAge.ToString();
}
}
<asp:GridView ID="UserInfoGrid" runat="server" AutoGenerateColumns="False" CellPadding="3"
DataKeyNames="userid" DataSourceID="DataSrcUserInfo"
AllowPaging="True" OnRowDataBound="UserInfoGrid_RowDataBound"
OnRowUpdated="Update" OnRowDeleted="Delete" PageSize="10" >
can anyone help me with this
Thanks,
First of all, shouldn't the code your are showing be in the RowUpdating event handler? As for the error you are getting, its obviously due to a bad formatted string in the Birthday cell.
Have you checked for empty strings? I'm guessing you are getting the exception even before the GridView renders on screen as its in the RowDataBound event handler which fires when the GridView is loading.
I have a GridView with a DataSource (SQL Database). I want to hide a column, but still be able to access the value when I select the record. Can someone show me how to do this?
This is the column I want to hide and still want to access its value:
<asp:BoundField DataField="Outlook_ID" HeaderText="OutlookID" />
I tried everything to hide the column (property Visible="false"), but I can't access its value.
<head runat="server">
<title>Accessing GridView Hidden Column value </title>
<style type="text/css">
.hiddencol
{
display: none;
}
</style>
<asp:BoundField HeaderText="Email ID" DataField="EmailId" ItemStyle-CssClass="hiddencol" HeaderStyle-CssClass="hiddencol" >
</asp:BoundField>
ArrayList EmailList = new ArrayList();
foreach (GridViewRow itemrow in gvEmployeeDetails.Rows)
{
EmailList.Add(itemrow.Cells[YourIndex].Text);
}
If I am not mistaken, GridView does not hold the values of BoundColumns that have the attribute visible="false". Two things you may do here, one (as explained in the answer from V4Vendetta) to use Datakeys. Or you can change your BoundColumn to a TemplateField. And in the ItemTemplate, add a control like Label, make its visibility false and give your value to that Label.
Define a style in css:
.hiddencol { display: none; }
Then add the ItemStyle-CssClass="hiddencol" and the HeaderStyle-CssClass="hiddencol" attribute to the grid field:
<asp:BoundField DataField="ID" HeaderText="ID" ItemStyle-CssClass="hiddencol" HeaderStyle-CssClass="hiddencol" ClientIDMode="Static" />
You can use DataKeys for retrieving the value of such fields, because (as you said) when you set a normal BoundField as visible false you cannot get their value.
In the .aspx file set the GridView property
DataKeyNames = "Outlook_ID"
Now, in an event handler you can access the value of this key like so:
grid.DataKeys[rowIndex]["Outlook_ID"]
This will give you the id at the specified rowindex of the grid.
You can do it programmatically:
grid0.Columns[0].Visible = true;
grid0.DataSource = dt;
grid0.DataBind();
grid0.Columns[0].Visible = false;
In this way you set the column to visible before databinding, so the column is generated.
The you set the column to not visible, so it is not displayed.
If you do have a TemplateField inside the columns of your GridView and you have, say, a control named blah bound to it. Then place the outlook_id as a HiddenField there like this:
<asp:TemplateField HeaderText="OutlookID">
<ItemTemplate>
<asp:Label ID="blah" runat="server">Existing Control</asp:Label>
<asp:HiddenField ID="HiddenOutlookID" runat="server" Value='<%#Eval("Outlook_ID") %>'/>
</ItemTemplate>
</asp:TemplateField>
Now, grab the row in the event you want the outlook_id and then access the control.
For RowDataBound access it like:
string outlookid = ((HiddenField)e.Row.FindControl("HiddenOutlookID")).Value;
Do get back, if you have trouble accessing the clicked row. And don't forget to mention the event at which you would like to access that.
You can make the column hidden on the server side and for some reason this is different to doing it the aspx code. It can still be referenced as if it was visible. Just add this code to your OnDataBound event.
protected void gvSearchResults_DataBound(object sender, EventArgs e)
{
GridView gridView = (GridView)sender;
if (gridView.HeaderRow != null && gridView.HeaderRow.Cells.Count > 0)
{
gridView.HeaderRow.Cells[UserIdColumnIndex].Visible = false;
}
foreach (GridViewRow row in gvSearchResults.Rows)
{
row.Cells[UserIdColumnIndex].Visible = false;
}
}
Leave visible columns before filling the GridView. Fill the GridView and then hide the columns.
Here is how to get the value of a hidden column in a GridView that is set to Visible=False: add the data field in this case SpecialInstructions to the DataKeyNames property of the bound GridView , and access it this way.
txtSpcInst.Text = GridView2.DataKeys(GridView2.SelectedIndex).Values("SpecialInstructions")
That's it, it works every time very simple.
I have a new solution hide the column on client side using css or javascript or jquery.
.col0
{
display: none !important;
}
And in the aspx file where you add the column you should specify the CSS properties:
<asp:BoundField HeaderText="Address Key" DataField="Address_Id" ItemStyle-CssClass="col0" HeaderStyle-CssClass="col0" > </asp:BoundField>
I used a method similar to user496892:
SPBoundField hiddenField = new SPBoundField();
hiddenField.HeaderText = "Header";
hiddenField.DataField = "DataFieldName";
grid.Columns.Add(hiddenField);
grid.DataSource = myDataSource;
grid.DataBind();
hiddenField.Visible = false;
I found this solution, an elegant(IMO) quick 2 parter.
1.
On your gridview, add a column as normal, no need to do anything differently:
<asp:BoundField DataField="AccountHolderName" HeaderText="Account Holder"
ReadOnly="true"/>
You can keep the header text if this is useful to you for later processing.
2.
In the rowdatabound method for the grid hide the header, footer and row for that column index:
if (e.Row.RowType == DataControlRowType.Header)
{
e.Row.Cells[10].Visible = false;
}
if (e.Row.RowType == DataControlRowType.Footer)
{
e.Row.Cells[10].Visible = false;
}
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Cells[10].Visible = false;
}
You can do it code behind.
Set visible= false for columns after data binding .
After that you can again do visibility "true" in row_selection function from grid view .It will work!!
I searched a lot but no luck. The most of them was working with some errors. Finally I used this code and it worked for me.
probably you should change 1 to some other value. for me I would hide second col.
protected void FoundedDrGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType!=DataControlRowType.Pager)e.Row.Cells[1].Visible = false;
}
I just set the width to 0. and it works.
columns.AddFor(m => m.Id).Name("hide-id").Width(0);
When I want access some value from GridView before GridView was appears.
I have a BoundField and bind DataField nomally.
In RowDataBound event, I do some process in that event.
Before GridView was appears I write this:
protected void GridviewLecturer_PreRender(object sender, EventArgs e)
{
GridviewLecturer.Columns[0].Visible = false;
}