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;
}
}
}
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");
}
}
User contributions licensed under CC BY-SA 3.0