Index error when deleting and creating an object in SQLite's table

78 Views Asked by At

C# and .net MAUI beginner here.

I am struggling with resolving the problem of Index being out of range when I delete the object in the SQLite database and create any new objects in replacement.

My app contains 2 Pages and 2 additional classes with the code behind.

The problem seems to be in the db_refresh on MainPage method where eachTerm count is not decreased compared to the termlist count causing Index to error out. Here is the error syntax:

System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')'

However, the proper number of buttons is being generated in the generateInterface method.

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    public static List<Term> termList = new List<Term>();
    public static string dbLocation = Path.Combine(FileSystem.AppDataDirectory, "MyData.db");
    public MainPage()
    {
        File.Delete(dbLocation);
        dbActions.initiateDbTables();
        InitializeComponent();
        db_refresh();
        generateInterface();
    }
    protected override void OnAppearing()
    {
        AppShell.SetBackgroundColor(this, Color.FromRgb(0, 0, 0));
        db_refresh();
        generateInterface();
    }
    public static void db_refresh()
    {
        termList.Clear();
        var dataBase = new SQLiteConnection(dbLocation);
        var queriedTerm = dataBase.Query<Term>("SELECT * FROM Terms");
        foreach (Term eachTerm in queriedTerm)
        {
           termList.Add(eachTerm);
        }
    }
    public void generateInterface()
    {

        termView.Children.Clear();

        foreach (Term myTerm in termList)
        {
            Button termNameButton = new Button
            {
                Text = myTerm.termName,
                BackgroundColor = Colors.Green,
                TextColor = Colors.White,
                FontAttributes = FontAttributes.Bold,
            };
            termNameButton.Clicked += async (sender, e) =>
            {
                await Navigation.PushAsync(new TermPage(myTerm.termId));
            };
            termView.Children.Add(termNameButton);
        }

        Button termAddButton = new Button()
        {
            Text = "Add Term",
            BackgroundColor = Colors.Black,
            TextColor = Colors.White,
            FontAttributes = FontAttributes.Bold,
        };
        termAddButton.Clicked += void (sender, args) => clickNewTerm();
        termView.Children.Add(termAddButton);
    }
    public void clickNewTerm()
    {
        dbActions.addNewDbTerm();
        generateInterface();
    }
}

The delete Term method is located in the separated page (TermPage) accessed when I click on the Terms button in the MainScreen. Here is the code of the TermPage:

public Term currentTerm;
public SQLiteConnection dbConnect = new SQLiteConnection(MainPage.dbLocation);
public TermPage(int termId)
{
    InitializeComponent();
    ButtonAdd();
    Term myTerm = MainPage.termList[termId - 1];
    currentTerm = myTerm;
    termName.Text = currentTerm.termName;
}
private void ButtonAdd()
{
    Button deleteTermButton = new Button()
    {
        Text = "Delete Term",
        BackgroundColor = Colors.Red,
        FontAttributes = FontAttributes.Bold,
    };
    deleteTermButton.Clicked += void (sender, args) => actionDeleteTerm();
    TermPageView.Children.Add(deleteTermButton);
}
public async void actionDeleteTerm()
{
    dbConnect.Delete(currentTerm);
    MainPage.db_refresh();
    await Navigation.PopAsync();
}

Here is the class that adds a new Term:

public class dbActions
{
    public static void initiateDbTables()
    {
        var dbLocation = Path.Combine(FileSystem.AppDataDirectory, "MyData.db");
        var dbConnect = new SQLiteConnection(dbLocation);
        dbConnect.CreateTable<Term>();
    }
    public static void addNewDbTerm()
    {
        var dbConnect = new SQLiteConnection(MainPage.dbLocation);
        var dbQuery = dbConnect.Query<Term>($"SELECT * FROM Terms ORDER BY termId DESC LIMIT 1");
        if (dbQuery.Count != 0)
        {
            Term topTerm = dbQuery.First();
            string termName = "Term " + (topTerm.termId + 1).ToString();
            Term newTerm = new Term(termName, DateTime.Now, DateTime.Now.AddDays(60));
            dbConnect.Insert(newTerm);
            MainPage.db_refresh();
        }
        else
        {
            Term newTerm = new Term("Term1", DateTime.Now, DateTime.Now.AddDays(60));
            dbConnect.Insert(newTerm);
            MainPage.db_refresh();
        }
    }
}

I tried to use termList.Clear() to refresh the Index, but I am not sure if that's the correct approach.

2

There are 2 best solutions below

2
Jason On BEST ANSWER

to retrieve an item by id from a list of objects, do this

Term myTerm = MainPage.termList.First(t => t.termId == termId);
0
garlando90 On

Well, I guess I had to post the question in order to find the answer myself lol. I finally fixed the issue modifying the termId prior parsing it to the TermPage with this line:

int termId = termList.IndexOf(myTerm) + 1;

and then instead of parsing myterm.termId I parsed the termId variable.

await Navigation.PushAsync(new TermPage(termId));