You need to create a custom gridview control that inherits from GridView. Without the DataSourceControl, the gridview does not have knowledge of the total number of records that could potentially be bound to the control. If you bind 10 out of 100 records and you set the PageSize property to 10, the gridview only knows that there are 10 records which will be less than or equal to the PageSize and the pager control will not display. In order for your gridview to show the pager, it has to know the total number of records that could potentially be retrieved. By inheriting the gridview and overriding the InitializePager method, we can intercept the pagedDataSource and modify the AllowCustomPaging and VirtualCount methods.
This is the one I created
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace cly.Web.CustomControls
{
public class clyGridView : GridView
{
private const string _virtualCountItem = "bg_vitemCount";
private const string _sortColumn = "bg_sortColumn";
private const string _sortDirection = "bg_sortDirection";
private const string _currentPageIndex = "bg_pageIndex";
public clyGridView ()
: base()
{
}
#region Custom Properties
[Browsable(true), Category("NewDynamic")]
[Description("Set the virtual item count for this grid")]
public int VirtualItemCount
{
get
{
if (ViewState[_virtualCountItem] == null)
ViewState[_virtualCountItem] = -1;
return Convert.ToInt32(ViewState[_virtualCountItem]);
}
set
{
ViewState[_virtualCountItem] = value;
}
}
public string GridViewSortColumn
{
get
{
if (ViewState[_sortColumn] == null)
ViewState[_sortColumn] = string.Empty;
return ViewState[_sortColumn].ToString();
}
set
{
if (ViewState[_sortColumn] == null || !ViewState[_sortColumn].Equals(value))
GridViewSortDirection = SortDirection.Ascending;
ViewState[_sortColumn] = value;
}
}
public SortDirection GridViewSortDirection
{
get
{
if (ViewState[_sortDirection] == null)
ViewState[_sortDirection] = SortDirection.Ascending;
return (SortDirection)ViewState[_sortDirection];
}
set
{
ViewState[_sortDirection] = value;
}
}
private int CurrentPageIndex
{
get
{
if (ViewState[_currentPageIndex] == null)
ViewState[_currentPageIndex] = 0;
return Convert.ToInt32(ViewState[_currentPageIndex]);
}
set
{
ViewState[_currentPageIndex] = value;
}
}
private bool CustomPaging
{
get { return (VirtualItemCount != -1); }
}
#endregion
#region Overriding the parent methods
public override object DataSource
{
get
{
return base.DataSource;
}
set
{
base.DataSource = value;
// store the page index so we don't lose it in the databind event
CurrentPageIndex = PageIndex;
}
}
protected override void OnSorting(GridViewSortEventArgs e)
{
//Store the direction to find out if next sort should be asc or desc
SortDirection direction = SortDirection.Ascending;
if (ViewState[_sortColumn] != null && (SortDirection)ViewState[_sortDirection] == SortDirection.Ascending)
{
direction = SortDirection.Descending;
}
GridViewSortDirection = direction;
GridViewSortColumn = e.SortExpression;
base.OnSorting(e);
}
protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
{
// This method is called to initialise the pager on the grid. We intercepted this and override
// the values of pagedDataSource to achieve the custom paging using the default pager supplied
if (CustomPaging)
{
pagedDataSource.VirtualCount = VirtualItemCount;
pagedDataSource.CurrentPageIndex = CurrentPageIndex;
}
base.InitializePager(row, columnSpan, pagedDataSource);
}
protected override object SaveViewState()
{
//object[] state = new object[3];
//state[0] = base.SaveViewState();
//state[1] = this.dirtyRows;
//state[2] = this.newRows;
//return state;
return base.SaveViewState();
}
protected override void LoadViewState(object savedState)
{
//object[] state = null;
//if (savedState != null)
//{
// state = (object[])savedState;
// base.LoadViewState(state[0]);
// this.dirtyRows = (List<int>)state[1];
// this.newRows = (List<int>)state[2];
//}
base.LoadViewState(savedState);
}
#endregion
public override string[] DataKeyNames
{
get
{
return base.DataKeyNames;
}
set
{
base.DataKeyNames = value;
}
}
public override DataKeyArray DataKeys
{
get
{
return base.DataKeys;
}
}
public override DataKey SelectedDataKey
{
get
{
return base.SelectedDataKey;
}
}
}
}
Then when you are binding the data:
gv.DataSource = yourListOrWhatever
gv.VirtualItemCount = numOfTotalRecords;
gv.DataBind();
If you want to avoid postback, uses jQuery like here:
http://jquerybyexample.blogspot.com/2012/04/how-to-filter-gridview-records-using.html
An alternative is AJAX, but at the end of the story it is a postback-like approach.
Finally using postback you can do it in several ways by dynamically setting the GridView filter before the GridView loads. This can be achieved with the Page load event, the OnSelecting of the associated datasource (if any), or similar.
Here it is an extraction of the aspx:
<asp:CheckBox ID="CheckBox1" runat="server" Text="A" />
<asp:CheckBox ID="CheckBox2" runat="server" Text="B" />
<asp:CheckBox ID="CheckBox3" runat="server" Text="C" />
<asp:CheckBox ID="CheckBox4" runat="server" Text="D" />
<hr />
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
DataSourceID="sqlDataSourceGridView" AutoGenerateColumns="False"
CssClass="GridViewStyle" GridLines="None" Width="650px" >
<Columns>
<asp:BoundField DataField="CompanyName" HeaderText="Company" ItemStyle-Width="200px" />
<asp:BoundField DataField="ContactName" HeaderText="Name" ItemStyle-Width="125px"/>
<asp:BoundField DataField="City" HeaderText="city" ItemStyle-Width="125px" />
<asp:BoundField DataField="Country" HeaderText="Country" ItemStyle-Width="125px" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSourceGridView" runat="server"
ConnectionString="<%$ ConnectionStrings:northWindConnectionString %>"
SelectCommand="SELECT [CustomerID], [CompanyName], [ContactName], [City], [Country] FROM [Customers]"
OnSelecting="SqlDataSourceGridView_Selecting">
<FilterParameters>
<asp:ControlParameter ControlID="checkbox1" Name="CompanyName" PropertyName="Checked" ConvertEmptyStringToNull="false" />
</FilterParameters>
</asp:SqlDataSource>
Note the OnSelecting event and note that there isn't any filter preset.
Now in the code behind set dynamically the filter:
protected void SqlDataSourceGridView_Selecting(object sender, SqlDataSourceSelectingEventArgs e) {
SqlDataSourceGridView.FilterExpression = string.Empty;
if (CheckBox1.Checked) {
SqlDataSourceGridView.FilterExpression += "(CompanyName=1)";
}
if (CheckBox2.Checked) {
if (!string.IsNullOrEmpty(SqlDataSourceGridView.FilterExpression)) SqlDataSourceGridView.FilterExpression += " OR ";
SqlDataSourceGridView.FilterExpression += "(B=1)";
}
if (CheckBox3.Checked) {
if (!string.IsNullOrEmpty(SqlDataSourceGridView.FilterExpression)) SqlDataSourceGridView.FilterExpression += " OR ";
SqlDataSourceGridView.FilterExpression += "(C=1)";
}
if (CheckBox4.Checked) {
if (!string.IsNullOrEmpty(SqlDataSourceGridView.FilterExpression)) SqlDataSourceGridView.FilterExpression += " OR ";
SqlDataSourceGridView.FilterExpression += "(D=1)";
}
}
If you don't like the OnSelecting event, you can do the same in the PageLoad:
protected void Page_Load(object sender, EventArgs e) {
// here same code of above
// . . .
}
I didn't test it so verify minor errors.
Best Answer
You can use Container.DataItem with a GridView - what you've got there looks fine. What error are you getting?
This link might also help: What's the deal with DataBinder.Eval and Container.DataItem?