Array is not accessible inside of a dynamic button

-2

I am trying to access an array inside a button I am creating when a new object is created, but the button goes out of array boundaries when I am using him (but accessing the very same index outside of the button yields no problem)

Relevant code (see the category and expense class below):

    public void updateExpensesLabels()
    {
        deleteExpensesLabels();
        for (int i = 0; i < categories.Length; i++)
        {
            if (categories[i] != null)
            {
                categories[i].test();
                addExpense.Click += (s, e) =>
                {
                    categories[i].createNewExpense(Convert.ToInt32(expenseAmount.Text), Convert.ToString(expenseName.Text));
                };
             }
         }
     }

Note that the categories[i] goes trough with no issues and prints the random text it should, but when I have put the test inside the button, the problem crushes when I click the button.

Edit: I made the test a bit more obvious, this time, the output of the code is "The object is not null outside of the button" and than crushes because of index out of array

            if (categories[i] == null)
            {
                MessageBox.Show("Its null outside the button code");
            }
            else
            {
                MessageBox.Show("Its not null outside the button code");
            }
            addExpense.Click += (s, e) =>
            {
                if (categories[i] == null)
                {
                    MessageBox.Show("Its null inside the button code");
                }
                categories[i].test();
                categories[i].createNewExpense(Convert.ToInt32(expenseAmount.Text), Convert.ToString(expenseName.Text));
            };

Edit 2: The exception is System.IndexOutOfRangeException The details -

System.IndexOutOfRangeException occurred
  HResult=0x80131508
  Message=האינדקס נמצא מחוץ לגבולות המערך.
  Source=Budget Managment Prog
  StackTrace:
   at Budget_Managment_Prog.Form1.<>c__DisplayClass21_0.<updateExpensesLabels>b__0(Object s, EventArgs e) in C:\Users\user\OneDrive\Budget Management Prog\Budget Managment Prog\Budget Managment Prog\Form1.cs:line 213
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at Budget_Managment_Prog.Program.Main() in C:\Users\user\OneDrive\Budget Management Prog\Budget Managment Prog\Budget Managment Prog\Program.cs:line 19

Forms1 -

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Budget_Managment_Prog
{
        /// <summary>
        /// Expenses Section
        /// </summary>
        Category[] categories = new Category[0];
        TabPage[] categoryTab = new TabPage[0];
        Label[] expenseLabel = new Label[0];
        private void addCategoryButton_Click(object sender, EventArgs e)
        {
            increaseCategories();
            categories[Category.categoryNum] = new Category(Category.categoryNum, newCategoryTextBox.Text);
            Category.categoryNum++;
            increaseTabs();
            updateExpensesLabels();
        }

        private void increaseTabs()
        {
            TabPage[] temp = new TabPage[categoryTab.Length + 1];
            for (int i = 0; i < categoryTab.Length; i++)
            {
                temp[i] = categoryTab[i];
            }
            categoryTab = temp;
        }

        private void increaseCategories()
        {
            Category[] temp = new Category[categories.Length + 1];
            for (int i = 0; i < categories.Length; i++)
            {
                temp[i] = categories[i];
            }
            categories = temp;
        }

        public void updateExpensesLabels()
        {
            deleteExpensesLabels();
            for (int i = 0; i < categories.Length; i++)
            {
                if (categories[i] != null)
                {

                    categoryTab[i] = new TabPage();
                    categoryTab[i].Text = categories[i].name;
                    categoryTabControl.Controls.Add(categoryTab[i]);
                    Label addExpenseLabel = new Label(); addExpenseLabel.Text = "New Expense Here?";
                    addExpenseLabel.AutoSize = true;
                    addExpenseLabel.Top = 10; addExpenseLabel.Left = 15; categoryTab[i].Controls.Add(addExpenseLabel);
                    Label nameLabel = new Label(); nameLabel.Text = "Name:";
                    nameLabel.AutoSize = true;
                    nameLabel.Top = 25; nameLabel.Left = 25; categoryTab[i].Controls.Add(nameLabel);
                    Label amountLabel = new Label(); amountLabel.Text = "Money:";
                    amountLabel.AutoSize = true;
                    amountLabel.Top = 25; amountLabel.Left = 250; categoryTab[i].Controls.Add(amountLabel);
                    TextBox expenseName = new TextBox(); expenseName.Top = 50; expenseName.Left = 25; categoryTab[i].Controls.Add(expenseName);
                    TextBox expenseAmount = new TextBox(); expenseAmount.Top = 50; expenseAmount.Left = 250; categoryTab[i].Controls.Add(expenseAmount);
                    categories[i].test();
                    Button addExpense = new Button();
                    addExpense.Click += (s, e) =>
                    {
                        categories[i].createNewExpense(Convert.ToInt32(expenseAmount.Text), Convert.ToString(expenseName.Text));
                    };
                    categoryTab[i].Controls.Add(addExpense);
                    int entries = 0;
                    int labelNum = 0;
                    for (int j = 0; j < categories[i].expenses.Length; j++)
                    {
                        expenseLabel[labelNum] = new Label();
                        expenseLabel[labelNum].Text = Convert.ToString(categories[i].expenses[labelNum].num);
                        expenseLabel[labelNum].Top = 80 + (30 * entries); expenseLabel[labelNum].Left = 25;
                        categoryTab[i].Controls.Add(expenseLabel[labelNum]);
                        increaseLabelArray();
                        labelNum++;


                    }
                }
            }
        }

        private void deleteExpensesLabels()
        {
            for (int i = 0; i< categoryTab.Length; i++)
            {
                categoryTabControl.Controls.Remove(categoryTab[i]);
            }
        }

        private void increaseLabelArray()
        {
            Label[] temp = new Label[expenseLabel.Length + 1];
            for (int i = 0; i < expenseLabel.Length; i++)
            {
                temp[i] = expenseLabel[i];
            }
            expenseLabel = temp;
        }
    }
}

Category -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace Budget_Managment_Prog
{
    class Category
    {
        private int numOfExpenses = 0;
        public Expense[] expenses = new Expense[0];
        public static int categoryNum = 0;
        public string name;
        public Category(int num1, string name1)
        {
            categoryNum = num1;
            name = name1;
        }

        public void createNewExpense( int expense2, string name2)
        {

            increaseArray();
            expenses[numOfExpenses] = new Expense(numOfExpenses, expense2, name2);
            numOfExpenses ++;           


        }

        public void deleteExpense(int num)
        {
            if (num > expenses.Length || num < 1)
            {
                MessageBox.Show("Invalid Entry for deletion, make sure the number is not bigger than the biggest person or smaller than 1");
            }
            else
            {
                Expense[] temp = new Expense[expenses.Length - 1];
                for (int i = 0; i < expenses.Length; i++)
                {
                    if (expenses[i].num < num)
                    {
                        temp[i] = expenses[i];
                    }
                    if (expenses[i].num > num)
                    {
                        expenses[i].num--;
                        temp[i - 1] = expenses[i];
                    }
                }
                expenses = temp;
                numOfExpenses--;
            }
        }
        public void increaseArray()
        {
            Expense[] temp = new Expense[expenses.Length + 1];
            for (int i = 0; i < expenses.Length; i++)
            {
                temp[i] = expenses[i];
            }
            expenses = temp;

        }

        public void test()
        {
            MessageBox.Show("The Problem is in category or expense classes");
        }
    }
}

Expense -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Budget_Managment_Prog
{
    class Expense
    {
        public int num;
        public int expense;
        public string name;
        public Expense(int num1, int expense1, string name1)
        {
            num = num1;
            expense = expense1;
            name = name1;
        }
    }


}
c#
arrays
winforms
asked on Stack Overflow May 22, 2017 by Tomer • edited May 23, 2017 by Tomer

1 Answer

2

UPDATED

I found your problem. It's in this categories[i]. If you debug the program you will see that when you add new Category your i is 0 and your categories[i].test() will work normally. But the problem is in the fact that your button click is always after the loop's iteration , in other words when button click works i is already equal to 1 and your categories[i] will go out of bounds.
If you change the part in your code where you add button to this you won't get exception any more:

categories[i].test();
var number = i;
Button addExpense = new Button();
addExpense.Click += (s, e) =>
{                       
    categories[number].createNewExpense(Convert.ToInt32(expenseAmount.Text), Convert.ToString(expenseName.Text));
};

You have declared

public Expense[] expenses = new Expense[0]; 

then you are trying to do this

expenses[numOfExpenses] = new Expense(numOfExpenses, expense2, name2);

where the numOfExpenses is out of expenses length as it is empty array as you have declared.

I suggest you to use List<Expense> instead of Expense[], so it won't be limited by the number that you give while initialization and when you will need to add new Expense you will just use expenses.Add(new Expense(numOfExpenses, expense2, name2)).

Here is example how you can do it

class Category
{
    public List<Expense> expenses = new List<Expense>();
    public static int categoryNum = 0;
    public string name;
    public Category(int num1, string name1)
    {
        categoryNum = num1;
        name = name1;
    }

    public void createNewExpense(int expense2, string name2)
    {
        expenses.Add(new Expense(expenses.Count, expense2, name2));
    }

    public void deleteExpense(int num)
    {
        if (num > expenses.Count || num < 1)
        {
            MessageBox.Show("Invalid Entry for deletion, make sure the number is not bigger than the biggest person or smaller than 1");
        }
        else
        {
            expenses.RemoveAt(num);
        }
    }
    public void test()
    {
        MessageBox.Show("The Problem is in category or expense classes");
    }
}
answered on Stack Overflow May 22, 2017 by Samvel Petrosov • edited May 23, 2017 by Samvel Petrosov

User contributions licensed under CC BY-SA 3.0