Mufaka
Mufaka

Reputation: 3444

Using BindingNavigator without BindingSource

I have an application where paging is done in the database. That is, the call to retrieve a list of items includes the page number, the page size, and will return only that pages' data. For example:

ItemCollection items = ListAllItems(1, 20); // page 1, show 20 items per page

ItemCollection includes a PagingUtil property that is a class that contains properties to support paging without retrieving all records.

public class PagingUtil
{
    public int StartRow { get; private set; }

    public int EndRow { get; private set; }

    public int TotalPages { get; private set; }

    public bool HasPrevPage { get; private set; }

    public bool HasNextPage { get; private set; }

    public int TotalCount { get; private set; }

    private PagingUtil() {}

    public PagingUtil(int pageNumber, int visiblePerPage, int totalCount) 
    {
            ... logic for setting property values here ...
        }
    }

I would like to use the BindingNavigator Control UI in a Windows Forms application without having to specify a BindingSource.

The problem is, the BindingNavigator will only be rendered as enabled if a BindingSource is set. Setting the Enabled property to true both in the designer and in code is not respected and I cannot seem to find a workaround or alternative stock control.

Is it possible to use the BindingNavigator this way? I can create a custom paging control if needed, but would prefer not to if I don't have to.

Upvotes: 3

Views: 8291

Answers (2)

eddwo
eddwo

Reputation: 311

I tried to do a similar thing today, and just ended up inventing some data objects for the BindingNavigator to manage which then represented the pages of the actual data in the database. A BindingSource can be given an IListSource as its DataSource, from which it will then draw the list of data to bind against.

class PageList : System.ComponentModel.IListSource
{
    private const int itempagesize = 250;
    private long totalitems;

    public PageList(string tablename, long totalrecords)
    {
        this.TableName = tablename;
        totalitems = totalrecords;
    }

    public bool ContainsListCollection { get; protected set; }

    public System.Collections.IList GetList()
    {
        List<ItemPage> pages = new List<ItemPage>();
        int totalPages = (int)Math.Ceiling((double)totalitems / (double)itempagesize);
        pages.AddRange(Enumerable.Range(0, totalPages).Select(
            pageidx => new ItemPage(itempagesize, pageidx * itempagesize)));
        return pages;
    }

    public string TableName { get; protected set; }


    public class ItemPage
    {
        public ItemPage(int limit, int offset)
        {
            this.Limit = limit;
            this.Offset = offset;
        }

        public readonly int Limit;
        public readonly int Offset;
    }
}

So I have a BindingNavigator tied to a BindingSource, and when I want to set the total number of available pages of data I just do a:

bsDataPages.DataSource = new PageList(tableName, recordCount);

Then the binding source event handler is fired when the navigator is used

    private void bsDataPages_CurrentChanged(object sender, EventArgs e)
    {
        PageList list = bsDataPages.DataSource as PageList;
        PageList.ItemPage page = bsDataPages.Current as PageList.ItemPage;
        var items = m_datastore.GetTableItems(m_conn, 
            list.TableName,page.Limit,page.Offset);
    }

and I can go and fetch that page of data from the database.

Upvotes: 6

Mufaka
Mufaka

Reputation: 3444

There was no way to override the binding behavior in the BindingNavigator which is comprised of a ToolStrip and several controls to support navigation. I ended up copying the controls from the BindingNavigator into a new ToolStrip and added my paging support there.

Upvotes: 3

Related Questions