I am looking for paging(Top,Bottom) functionality for gridview(or any databind controls)
i am using .net framework 2.0.
i would like to have pointers
thank you
solution:
i used jQuery plugin jquery.tablePagination.0.1.js for my solution
You can asp:repeater for this this can easily handle by Repeater control.
This aspx page code
<asp:Repeater ID="rptImages" runat="server" onitemcommand="rptImages_ItemCommand">
<ItemTemplate >
<div class="image"> <a ><asp:Image ID="Image1" runat="server" imageUrl=' <%# Eval("ImageUrl") %>' /></a> </div>
</ItemTemplate>
</asp:Repeater>
<asp:Repeater ID="rptPages" Runat="server"
onitemcommand="rptPages_ItemCommand">
<HeaderTemplate>
<table cellpadding="0" cellspacing="0" border="0">
<tr class="text">
<td><b style="color:White;">Page:</b> </td>
<td>
</HeaderTemplate>
<ItemTemplate>
<asp:LinkButton ID="btnPage" ForeColor="White"
CommandName="Page"
CommandArgument="<%#
Container.DataItem %>"
CssClass="text"
Runat="server"><%# Container.DataItem %>
</asp:LinkButton>
</ItemTemplate>
<FooterTemplate>
</td>
</tr>
</table>
</FooterTemplate>
</asp:Repeater>
this code behind page code
public void LoadData()
{
try
{
PagedDataSource pgitems = new PagedDataSource();
DataView dv = new DataView(dtImage);
pgitems.DataSource = dv;
pgitems.AllowPaging = true;
pgitems.PageSize = 8;
pgitems.CurrentPageIndex = PageNumber;
if (pgitems.PageCount > 1)
{
rptPages.Visible = true;
ArrayList pages = new ArrayList();
for (int i = 0; i < pgitems.PageCount; i++)
pages.Add((i + 1).ToString());
rptPages.DataSource = pages;
rptPages.DataBind();
}
else
rptPages.Visible = false;
rptImages.DataSource = pgitems;
rptImages.DataBind();
}
catch { }
}
public int PageNumber()
{
get
{
if (ViewState["PageNumber"] != null)
return Convert.ToInt32(ViewState["PageNumber"]);
else
return 0;
}
set
{
ViewState["PageNumber"] = value;
}
}
public void itemGet()
{
try
{
var Images = dataContext.sp_getCards(categoryId);
PagedDataSource pds = new PagedDataSource();
pds.DataSource = Images;
pds.AllowCustomPaging = true;
pds.AllowPaging = true;
pds.PageSize = 8;
pds.CurrentPageIndex = CurrentPage;
lblCurrentPage.Text = "Page: " + (CurrentPage + 1).ToString() + " of "
+ pds.PageCount.ToString();
// Disable Prev or Next buttons if necessary
//cmdPrev.Enabled = !pds.IsFirstPage;
//cmdNext.Enabled = !pds.IsLastPage;
rptImages.DataSource = pds;
rptImages.DataBind();
}
catch { }
}
protected void rptPages_ItemCommand(object source, RepeaterCommandEventArgs e)
{
try
{
PageNumber = Convert.ToInt32(e.CommandArgument) - 1;
LoadData();
}
catch { }
}
This will be hardly achievable in GridView because it uses rigid table structure with only single pager template. You need two - one on the top and one on the bottom. For such control you need Repeater (.NET 2.0) or ListView (.NET 3.5). When you have buttons placed you can handle their click or command events and rebind your grid to newly selected set of data. In repeater you will probably have to store current page and number of items per page somewhere (ViewState). If you want jQuery based paging (client side) with partial rendering you need to handle client side onclick and add AJAX call to get new page based on pushed button.
i used jQuery plugin jquery.tablePagination.0.1.js for my solution
refer this link
As others have said, I don't think this is a good job for GridView. I'd take a look at ListView or Repeater as they are better suited for something like this and quite easy to add custom pagination to.
Related
Please consider this scenario:
I have a simple page and I want to log all controls causing postback. I create this simple page. It contains a grid to show some URLs and when user click on an icon a new tab should open:
<form id="form1" runat="server">
<div>
<table style="width: 100%;">
<tr>
<td style="background-color: #b7ffbb; text-align: center;" colspan="2">
<asp:Button ID="Button3" runat="server" Text="Click Me First" Height="55px" OnClick="Button3_Click" />
</td>
</tr>
<tr>
<td style="background-color: #f1d8fe; text-align: center;" colspan="2">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" BackColor="White" OnRowCommand="GridView1_RowCommand">
<Columns>
<asp:BoundField DataField="SiteAddress" HeaderText="Address" />
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="ImageButton1" ImageUrl="~/download.png" runat="server" CommandArgument='<%# Eval("SiteAddress") %>' CommandName="GoTo" Height="32px" Width="32px" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</td>
</tr>
</table>
</div>
</form>
and code behind:
public partial class WebForm2 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button3_Click(object sender, EventArgs e)
{
List<Address> Addresses = new List<Address>()
{
new Address(){ SiteAddress = "https://google.com" },
new Address(){ SiteAddress = "https://yahoo.com" },
new Address(){ SiteAddress = "https://stackoverflow.com" },
new Address(){ SiteAddress = "https://learn.microsoft.com/}" }
};
GridView1.DataSource = Addresses;
GridView1.DataBind();
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "MyScript", "window.open('" + e.CommandArgument.ToString() + "', '_blank')", true);
}
}
class Address
{
public string SiteAddress { get; set; }
}
every thing is fine till here. Now I create a base class for all of my pages and add below codes for finding postback control:
public class MyPageBaseClass : Page
{
protected override void OnInit(EventArgs e)
{
if (!IsPostBack)
{
}
else
{
var ControlId = GetPostBackControlName(); <------
//Log ControlId
}
base.OnInit(e);
}
private string GetPostBackControlName()
{
Control control = null;
string ctrlname = Page.Request.Params["__EVENTTARGET"];
if (ctrlname != null && ctrlname != String.Empty)
{
control = Page.FindControl(ctrlname);
}
else
{
foreach (string ctl in Page.Request.Form)
{
Control c;
if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
{
string ctrlStr = ctl.Substring(0, ctl.Length - 2);
c = Page.FindControl(ctrlStr);
}
else
{
c = Page.FindControl(ctl);
}
if (c is System.Web.UI.WebControls.Button ||
c is System.Web.UI.WebControls.ImageButton)
{
control = c;
break;
}
}
}
if (control != null)
return control.ID;
else
return string.Empty;
}
}
and change this line:
public partial class WebForm2 : MyPageBaseClass
Now when I click on icons grid view disappears...(STRANGE...) and nothing happened. When I comment specified line then every thing will be fine...(STRANGE...).
In GetPostBackControlName nothings changed to Request but I don't know why this happened. I checked and I see if I haven't RegisterStartupScript in click event every thing is fine. Please help we to solve this problem.
Thanks
when I click on icons grid view disappears...
ASP.Net page class object instances only live long enough to serve one HTTP request, and each HTTP request rebuilds the entire page by default.
Every time you do a postback, you have a new HTTP request and therefore a new page class object instance and a completely new HTML DOM in the browser. Any work you've done for a previous instance of the page class — such as bind a list of addresses to a grid — no longer exists.
You could fix this by also rebuilding your grid code on each postback, but what I'd really do is skip the whole "RegisterStartupScript" mess and instead make the grid links open the window directly, without a postback at all.
The problem is related to OnInit event. I replaced it with OnPreLoad and every things is fine now.
For search engines: OnInit event has conflict with RegisterStartupScript
I have a web form where I need to group items/rows based on some criteria. It has multilevel grouping and that is why rendering items in the gird becomes very tedious process for the server.
Here is what I do currently. (This is for only 3 level).
protected void ResultGrid_PreRender(object sender, EventArgs e)
{
foreach (GridViewRow gdR in ResultGrid.Rows)
{
Label lblClass = (Label)gdR.FindControl("lblClass");
Label lblCategory = (Label)gdR.FindControl("lblCategory");
Label lblCompartment = (Label)gdR.FindControl("lblCompartment");
Panel pnlClassLinks = (Panel)gdR.FindControl("pnlClassLinks");
foreach (GridViewRow gdRIn in ResultGrid.Rows)
{
if (gdRIn.RowIndex != gdR.RowIndex)
{
Label lblClassIn = (Label)gdRIn.FindControl("lblClass");
Label lblCategoryIn = (Label)gdRIn.FindControl("lblCategory");
Label lblCompartmentIn = (Label)gdRIn.FindControl("lblCompartment");
if(lblClassIn.Text == lblClass.Text)
{
if(lblCategoryIn.Text == lblCategory.Text)
{
if(lblCompartmentIn.Text == lblCompartment.Text)
{
LinkButton lnkBtn = new LinkButton();
// lnkBtn Properties added
pnlClassLinks.Controls.Add(lnkBtn);
if (pnlClassLinks.Controls.Count > 2)
{
pnlClassLinks.Width = 150;
}
if (gdR.Visible)
{
dr.Visible = false;
}
}
}
}
}
}
LinkButton lnkGroupEdit = (LinkButton)gdR.FindControl("lnkGroupEdit");
lnkGroupEdit.OnClientClick = "editGroup();";
}
}
As it clearly shows, the rows iteration is too much, when the number of rows in gridview increases. So, is there any better way to do this?
You can create a GenericCollection. Include your customised properties like (width, cssClass, visibility...). Then bind this collection to the gridView as a dataSource.
gridView.DataSource= List_CustomModel;
gridView.DataBind();
this is a scope from a code i manipulate
`
<asp:TemplateField>
<HeaderTemplate>
<asp:Literal ID="LtBodac" runat="server" Text="BODACC" />
</HeaderTemplate>
<HeaderStyle CssClass="css-bodacc" />
<ItemTemplate>
<asp:TextBox Visible='<%#Eval("Bodacc") %>' ID="TbDateBodac" CssClass="datebox source-manuel css-bodacc CustomDateMercure" runat="server" Text='<%#Eval("DateBodac")%>' /><asp:HiddenField Visible='<%#Eval("Bodacc") %>' ID="HfOldDateBodac" runat="server" Value='<%#Eval("DateBodac")%>' /> </ItemTemplate>
</asp:TemplateField>
NB:#Eval("Bodacc") :Boddac is a property in my model.
I am doing a simple web site using asp.net and i am having troubles finding my or objects by id in the code behind in c#. I have something like this:
<asp:ListView ID="InternamentosListView" runat="server"
DataSourceID="InternamentosBD">
<LayoutTemplate>
<table id="camas">
<asp:PlaceHolder runat="server" ID="TablePlaceHolder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
the rest is irrelevant, and then i use this in the code behind:
Table table = (Table)FindControl("camas");
i also tried:
Table table = (Table)camas;
and
Control table= (Table)FindControl("camas");
and each one of this lines gives me Null. am i doing something wrong ?
EDIT: From your answers i did this:
<LayoutTemplate>
<table id="camas" runat="server">
</table>
</LayoutTemplate>
and tried all the things stated above. same result.
EDIT2: Whole Code:
C#
protected void Page_Load(object sender, EventArgs e)
{
Table table = (Table)FindControl("camas");
HiddenField NCamasHF = (HiddenField)FindControl("NCamas");
int NCamas = Convert.ToInt32(NCamasHF);
HiddenField NColunasHF = (HiddenField)FindControl("NColunas");
HiddenField CorMasc = (HiddenField)FindControl("CorMasc");
HiddenField CorFem = (HiddenField)FindControl("CorFem");
int NColunas = Convert.ToInt32(NColunasHF);
TableRow Firstrow = new TableRow();
table.Rows.Add(Firstrow);
for (int i = 1; i <= NCamas; i++)
{
if (i % NColunas == 0)
{
TableRow row = new TableRow();
table.Rows.Add(row);
TableCell cell = new TableCell();
cell.BackColor = System.Drawing.Color.LightGreen;
cell.CssClass = "celula";
row.Cells.Add(cell);
}
else
{
TableCell cell = new TableCell();
cell.BackColor = System.Drawing.Color.LightGreen;
cell.CssClass = "celula";
Firstrow.Cells.Add(cell);
}
}
}
asp.net
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:SqlDataSource
ID="ParametrosBD"
ConnectionString ="<%$ ConnectionStrings:principal %>"
ProviderName = "System.Data.SqlClient"
SelectCommand = "SELECT par_Id, par_NCamas, par_NColunas, par_CorMasculino, par_CorFeminino FROM Parametros WHERE par_Id=1"
runat="server">
</asp:SqlDataSource>
<asp:ListView ID="InternamentosListView" runat="server"
DataSourceID="InternamentosBD">
<LayoutTemplate>
<table id="camas" runat="server">
</table>
</LayoutTemplate>
<ItemTemplate>
<asp:HiddenField ID="NCamas" runat="server" Value='<%# Bind("par_NCamas") %>' />
<asp:HiddenField ID="NColunas" runat="server" Value='<%# Bind("par_NColunas") %>' />
<asp:HiddenField ID="CorMasc" runat="server" Value='<%# Bind("par_CorMasculino") %>' />
<asp:HiddenField ID="CorFem" runat="server" Value='<%# Bind("par_CorFeminino") %>' />
<tr id="cama"></tr>
</ItemTemplate>
</asp:ListView>
</asp:Content>
To expand on #Yura Zaletskyy's recursive find control method from MSDN -- you can also use the Page itself as the containing control to begin your recursive search for that elusive table control (which can be maddening, I know, I've been there.) Here is a bit more direction which may help.
using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI;
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Table table = (Table)FindControlRecursive(Page, "camas");
if (table != null)
{
//Do awesome things.
}
}
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn = FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
}
As you already added runat="server" is step 1. The second step is to find control by id, but you need to do it recursively. For example consider following function:
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn =
FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
None of the existing answers mention the obvious built-in solution, FindControl.
Detailed here, FindControl is a function that takes as a string the id of a control that is a child of the calling Control, returning it if it exists or null if it doesn't.
The cool thing is that you can always call it from the Page control which will look through all controls in the page. See below for an example.
var myTextboxControl = (TextBox)Page.FindControl("myTextboxControlID);
if (myTextboxControl != null) {
myTextboxControl.Text = "Something";
}
Note that the returned object is a generic Control, so you'll need to cast it before you can use specific features like .Text above.
You need to have runat="server" for you to be able to see it in the codebehind.
e.g.
<table id="camas" runat="server">
Ok. You have the table within a list view template. You will never find the control directly on server side.
What you need to do is find control within the items of list.Items array or within the item data bound event.
Take a look at this one- how to find control in ItemTemplate of the ListView from code behind of the usercontrol page?
When you're using a master page, then this code should work for you
Note that you're looking for htmlTable and not asp:Table.
// add the namespace
using System.Web.UI.HtmlControls;
// change the name of the place holder to the one you're using
HtmlTable tbl = this.Master.FindControl("ContentPlaceHolder1").FindControl("camas") as HtmlTable;
Best,
Benny
You need to add runat server like previously stated, but the ID will change based on ListView row. You can add clientidmode="Static" to your table if you expect only 1 table and find using InternamentosListView.FindControl("camas"); otherwise, you will need to add ItemDataBound event.
<asp:ListView ID="InternamentosListView" runat="server" DataSourceID="InternamentosBD" OnItemDataBound="InternamentosListView_ItemDataBound">
<LayoutTemplate>
<table id="camas">
<asp:PlaceHolder runat="server" ID="TablePlaceHolder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
You will need to introduce in code behind
InternamentosListView_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Table tdcamas = (Table)e.Item.FindControl("camas");
}
}
I'm using repeater to create dynamic ul li list
Is it possible to control class whether item is first or last?
Something like:
class="<%# if(Container.ItemIndex == 0)
{
class = ...
}
) %>"
by the way what does it really mean: <%# in ASP.NET
What is the difference between <%# and <%=?
It is quite easy to determine whether the item is first or not (Container.ItemIndex == 0), but to determine whether the element is last or not you have to use a custom property which will be initialized right with data binding:
protected int ItemCount { get; set; }
Here is a repeater example:
<asp:Repeater runat="server" ID="repeater">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li class="<%# GetItemClass(Container.ItemIndex) %>">
<%# Container.DataItem %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
here is an example of data binding:
public override void DataBind()
{
var data = new string[] { "first", "second", "third" };
this.ItemCount = data.Length;
repeater.DataSource = data;
repeater.DataBind();
}
and finally a helper method:
protected string GetItemClass(int itemIndex)
{
if (itemIndex == 0)
return "first";
else if (itemIndex == this.ItemCount - 1)
return "last";
else
return "other";
}
This will produce:
<ul>
<li class="first">
first
</li>
<li class="other">
second
</li>
<li class="last">
third
</li>
</ul>
I typically use something like the following:
<asp:Repeater ID="rptItems" runat="server" ViewStateMode="Disabled">
<ItemTemplate>
<li<%# Container.ItemIndex == ((IList)((Repeater)Container.Parent).DataSource).Count-1 ? " class='last'" : ""%>>
...
</li>
</ItemTemplate>
</asp:Repeater>
If possible, I'd recommend using something like jQuery for this as it makes implementing this type of functionality very easy. For example, you could have something like this:
<asp:Repeater id="MyRepeater" runat="server">
<HeaderTemplate><table class="MyRepeater"></HeaderTemplate>
<FooterTemplate></table></FooterTemplate>
<ItemTemplate><tr><td>My Data</td></tr></ItemTemplate>
</asp:Repeater>
$("table.MyRepeater tr:last").attr("class", "last");
Try somwthing like this, if you are not using jQuery
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:Label ID="Label1" CssClass='<%# Container.ItemIndex == 0 ? "first" : "notFirst" %>' runat="server" Text="Label"></asp:Label>
</ItemTemplate>
</asp:Repeater>
I modified nelsestu's solution and came up with:
<%# Container.ItemIndex == ((System.Data.DataTable)((Repeater)Container.Parent).DataSource).Rows.Count-1 ? "</div>" : string.Empty %>
As for your question on the difference between <%= and <%#, please see the following links:
Code Render Blocks:
http://msdn.microsoft.com/en-us/library/k6xeyd4z(v=vs.71).aspx
Data Binding Expression Syntax:
http://msdn.microsoft.com/en-us/library/bda9bbfx(v=vs.71).aspx
I wasn't able to use Alex's answer directly. Here are the modifications I made that worked for me. Using Alex's "repeater example" for the asp:Repeater tag, use this in the code behind:
private string[] data = new string[] { "first", "second", "third" };
protected int ItemCount { get; set; }
private void Page_Load(object sender, EventArgs e)
{
// normally one would fetch the data here right before binding like this:
// data = SomeService.SomeMethodToGetData();
repeater.DataSource = data;
repeater.DataBind();
}
public override void DataBind()
{
ItemCount = data.Count();
}
protected string GetItemClass(int itemIndex)
{
if (itemIndex == 0)
return "first";
else if (itemIndex == this.ItemCount - 1)
return "last";
else
return "other";
}
I usually do it like this for the last item
Public m_recordCount As Integer
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
ltrlTitle.Text = m_title
Using Context As New MyEntities
Dim m_lst = Context.getHotRecords(m_location).ToList
m_recordCount = m_lst.count()
rptListings.DataSource = m_lst
rptListings.DataBind()
End Using
End Sub
and here is how I use it in HTML markup
<div <%# IIf(m_recordCount - 1 = Container.ItemIndex, "class='clearBorder'", "")%>>
For those needing this in VB, here's what works for me.
<span runat="server" class='divider'
Visible="<%# Container.ItemIndex < DirectCast(DirectCast(Container.Parent,Repeater).DataSource,List(Of IList)).Count()-1 %>">|</span>
I needed a divider to show for all items except for the last one.
If your are using controls within your ItemTemplate you can do something like the following, add OnItemDataBound event.
<asp:Repeater ID="RptId" runat="server" OnItemDataBound="OnItemDataBound">
<ItemTemplate>
<asp:Panel runat="server" ID="PnlCtrlItem">
<%#Eval("Content") %>
</asp:Panel>
</ItemTemplate>
</asp:Repeater>
protected void OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemIndex == 0)
((Panel) e.Item.FindControl("PnlCtrlItem")).CssClass = "first";
//or the following to have your control indexed
((Panel) e.Item.FindControl("PnlCtrlItem")).CssClass = string.Format("item-{0}",e.Item.ItemIndex);
}
I'm trying to use the repeat without binding it to a datasource, is this possible?
<asp:Repeater runat="server" ID="rptPageNav">
<ItemTemplate>
<asp:HyperLink runat="server" CssClass="pageLink" ID="pageLink">#</asp:HyperLink>
</ItemTemplate>
</asp:Repeater>
Then in my code, I want to loop through adding the repeater item template for each link available.
for (int i = 0; i < thisTemplate.specification.pagination; i++)
{
}
So the end results should be something like:
<a class="pageLink" href="#">1</a>
<a class="pageLink" href="#">2</a>
<a class="pageLink" href="#">3</a>
<a class="pageLink" href="#">4</a>
Alternatively, if you want only single simple link you don't need Repeater IMO you can have simple Panel then create the links on the fly:
for (int i = 1; i < 5; i++) {
HyperLink link = new HyperLink();
link.CssClass = "pageLink";
link.NavigateUrl = "#";
link.Text = i.ToString();
MyPanel.Controls.Add(link);
}
Create an array of integers up to what you need and bind that to your repeater, using the value as the text for your hyperlink.
No, you have to bind a Repeater to some kind of datasource. Try using an array of ints as #Paddy suggests.
Incidentally, you'll need to modify the markup within the <ItemTemplate> tags to get your hyperlinks to display one above the other as in your example.
MSDN defines asp:Repeater as
A data-bound list control that allows
custom layout by repeating a specified
template for each item displayed in
the list.
Which essentially means we have to bind it to a datasource. Why dont you try and implemt something like this
Markup
<asp:Repeater runat="server" ID="rptPageNav">
<ItemTemplate>
<asp:HyperLink ID="pageLink" runat="server" CssClass="pageLink" NavigateUrl='<%# Eval("Link") %>'><%# Eval("Title") %></asp:HyperLink>
</ItemTemplate>
</asp:Repeater>
Code
public partial class Repeater : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<URL> urls = new List<URL>()
{
new URL(){ Link = "http://www.google.com", Title = "Google"},
new URL(){ Link = "http://www.yahoo.com", Title = "Yahoo"}
};
rptPageNav.DataSource = urls;
rptPageNav.DataBind();
}
}
}
public class URL
{
public string Link { get; set; }
public string Title { get; set; }
}