Search code examples
c#asp.netdatalist

ASP.NET Datalist Paging Index Error 'Index -6 is negative or over number of rows.'


When I click the btn_Last button I get this error:

System.IndexOutOfRangeException: 'Index -6 is negative or over number of rows.

Whenever I change the pagesize value, the value I change is the same as the index value in the error it gives.

public partial class mainpage : System.Web.UI.Page
{
    //string connection = "Data Source=localhost;Initial Catalog=Sefa;Integrated Security=True";

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            ItemsGet();
        }
    }

    PagedDataSource objPds = new PagedDataSource();

    private void ItemsGet()
    {
        SqlConnection baglanti = new SqlConnection(connection);
        string komut = string.Format("SELECT * FROM Users");

        baglanti.Open();

        SqlCommand command = new SqlCommand(komut, baglanti);
        SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
        DataSet dataSet = new DataSet();
        dataAdapter.Fill(dataSet);

        PagedDataSource objPds = new PagedDataSource();
        objPds.AllowPaging = true;
        objPds.PageSize = 6;

        objPds.DataSource = dataSet.Tables[0].DefaultView;
        objPds.CurrentPageIndex = CurrentPage;

        lblCurrentPage.Text = "Page: " + (CurrentPage + 1).ToString() + " of " + objPds.PageCount.ToString();
        btnFirst.Enabled = !objPds.IsFirstPage;
        btnPre.Enabled = !objPds.IsFirstPage;
        btnNext.Enabled = !objPds.IsLastPage;
        btnLast.Enabled = !objPds.IsLastPage;
        
        DataList2.DataSource = objPds;
        DataList2.DataBind();

        baglanti.Close();
    }

    protected void btnFirst_Click(object sender, EventArgs e)
    {
        CurrentPage = 0;
        ItemsGet();
    }

    protected void btnPre_Click(object sender, EventArgs e)
    {
        //if (CurrentPage > 0)
        //{
            CurrentPage -= 1;
            ItemsGet();
        //}
    }

    protected void btnNext_Click(object sender, EventArgs e)
    {
        //if (CurrentPage < objPds.PageCount - 1)
        //{
            CurrentPage += 1;
            ItemsGet();
        //}
    }

    protected void btnLast_Click(object sender, EventArgs e)
    {
        int lastPageIndex = objPds.PageCount - 1;
        CurrentPage = lastPageIndex;
        ItemsGet();
    }
    public int CurrentPage
    {
        get {
            object o = this.ViewState["_CurrentPage"];
            if (o == null)
            {
                return 0;
            }
            else
            {
                return (int)o;
            }
        }
        set {
            this.ViewState["_CurrentPage"] = value;
        }

    }
}

And to solve this problem, when I add the lines that are currently comments on the btnPre_Click button and the btnNext_Click button, the transition between the pages does not work, so those buttons also Decode.


Solution

  • Remember that every time you have a postback, which includes every event handler, you're working with a brand new instance of the class.

    That means the ItemsGet() method, which loads the data so the objPds.PageCount value will be correct, has not yet run when btnLast_Click is called.

    To fix this, you should separate ItemsGet() into two methods. The first will make the database call and set the data source. It should always run earlier in the page lifecycle, whether or not it's a postback. The other method will then handle the related operations of setting labels and showing the right buttons based on the current page and which event is in progress.

    Then button events then don't need to call the first of these methods; only the second, and you can know that data was initialized when they run.

    public void LoadData()
    {
        // adjusting the query a bit so I can demonstrate parameterized queries
        // Typically I would also specify the exact column names
        var sql = "SELECT * FROM Users WHERE ID= @ID";
        var dataSet = new DataSet();
    
        using (var cn = new SqlConnection(connection))
        using (var cmd = new SqlCommand(sql, cn))
        using (var da = new SqlDataAdapters(cmd))
        {
            // And normally the ID variable would be passed as an argument to the method.
            cmd.Parameters.Add("@ID", SqlDbType.Int).Value = someIDVariable;
    
            da.Fill(dataSet);
        } 
    
        // don't recreate the objPds instance.
        // It was already created with the class during field initialization
        objPds.AllowPaging = true;
        objPds.PageSize = 6;
        objPds.DataSource = dataSet.Tables[0].DefaultView
    }
    
    public void SetDataPage(int PageIndex)
    {
        objPds.CurrentPageIndex = PageIndex;
    
        lblCurrentPage.Text = $"Page: {PageIndex + 1} of {objPds.PageCount}";
        btnFirst.Enabled = !objPds.IsFirstPage;
        btnPre.Enabled = !objPds.IsFirstPage;
        btnNext.Enabled = !objPds.IsLastPage;
        btnLast.Enabled = !objPds.IsLastPage;
        
        DataList2.DataBind();
    }
    
    protected void Page_Load(object sender, EventArgs e)
    {
        LoadData();
    }
    
    // Only showing one of the click events
    protected void btnLast_Click(object sender, EventArgs e)
    {
        SetDataPage(objPds.PageCount - 1);
    }