I think we're kind of going off into the weeds here.
In a professional application, you'd have several layers of abstraction at work because there'd be a strong separation between data and UI. Moving a rung down the abstraction ladder, you would make a data class and a user control that can display that data class. Moving a rung further down, you'd have a data class and a set of controls used to display that data class. At the bottom of the abstraction ladder, you have parallel arrays. However, the complexity ladder is inverted. With layers of abstraction in place, you just say "display this data" and don't care about how it happens. With the user control, you still say "display this data". Without the user control, you say "put this property in this control, this property in this control, ...". With parallel arrays, you say "put the value from this array into this control, ...". The less abstraction you use, the harder it is to do anything. The more abstraction you use, the harder it is to understand how everything works together. You want something in the middle.
I don't think you need an array at all. You have stated that you want to be able to remove items. To remove an item from an array you have to shift all of the other elements to fill in the hole or write logic that recognizes holes and ignores them. This isn't unique to C#; this is true in every language that has arrays (though sometimes the language runtime has mechanisms to help.) It's good to know how arrays work, but 99% of the time it's better to work at a higher level of abstraction.
Another thing: structures are for advanced cases in .NET. They have value semantics and can hurt performance except in very specific scenarios. It is best to use classes by default and only switch to structures when you know you need them. Less than 1% of the code I write uses structures.
I'll demonstrate a solution at the 2nd lowest level of abstraction. This is the level that doesn't use a UserControl but still uses a class. You start by defining the data type you want to represent; in this case it's an
Employee with a name and ID:
Code:
public class Employee
{
public integer Id { get; set; }
public string Name { get; set; }
}
Since you want to add/remove employees, you really don't want to use an array. Arrays are the lowest-level collection type, and are optimized for data sets that are of a fixed or predictable size. For example, if you know there are always 10 employees, an array is appropriate. If there are always 10, 20, or 30 employees, an array is still appropriate. If there can be any number of employees and the number will change at runtime, arrays are inappropriate. The List<T> generic class represents a list data structure, which is like an array that can change its size on a whim. There's some performance implications, but part of List<T>'s implementation hides this. If you're unfamiliar with the "<T>" part, that means it's a
generic type. Generic types take a "type parameter" that controls how they behave. The best way to describe the difference is to compare it to an array:
Code:
int[] values = new int[10]; // 10-element array of integers
List<int> valuesList = new List<int>(); // ???-element list of integers
The type parameter in a list describes what the element type of the list will be. You can put any type in place of T, even List<T> itself, but you *must* replace T with a type before you can use it.
Now, that aside, let's talk about the form. Obviously you'll have a ListBox, I'm calling mine
lstEmployees. There will be two text boxes for the ID and name of the selected employee (
txtId,
txtName.) There will be a "remove" button that will remove an employee from the list (
btnRemove.) Anything else (labels, group boxes, etc.) is unimportant to the topic.
Step 1 is making a list of employees. To do this, I used a loop to make 10 employees; you'll likely be doing something else. After the list of employees is made, you have to do something with it. Windows Forms leads you to believe you have to put strings in a ListBox, but in reality the control can store *anything* so long as you tell it how to display the object. I'm going to put the whole list of employees into the ListBox directly. I also set the
DisplayMember property. By default, the ListBox just displays whatever its contents'
ToString() method returns. If you set
DisplayMember to a property name, the ListBox will look for a property with that name and use that instead. Here's what my
Load event handler looks like:
Code:
private void Form1_Load(object sender, EventArgs e)
{
// Get your list of employees and store them in the form; your method may vary.
for (int i = 0; i < 10; i++)
{
lstEmployees.Items.Add(new Employee() { Id = i, Name = "Employee " + i.ToString()});
}
lstEmployees.DisplayMember = "Name";
}
Instead of an array or list of employees, we have a ListBox filled with employees. The list box is told how to display an employee (it displays the name.) Running the form at this point gets us 10 employees in a list box. Yay!
Step 2 is getting information about the currently selected employee into the text boxes. To do this, watch one of the selection change events on the list box; I'm going to use
SelectedItemChanged. When the selected item changes, I'll get that item and put the appropriate values in the text boxes. Keep in mind that if nothing is selected, nothing should go in the text boxes:
Code:
private void lstEmployees_SelectedIndexChanged(object sender, EventArgs e)
{
txtId.Clear();
txtName.Clear();
Employee selectedEmployee = (Employee)lstEmployees.SelectedItem;
if (selectedEmployee != null)
{
txtId.Text = selectedEmployee.Id.ToString();
txtName.Text = selectedEmployee.Name;
}
}
In summary, this clears the old information then attempts to replace it with the new information. Notice that we didn't even have to fool with an array; in this case all we care about is the selected item, and the ListBox is capable of giving it to us. Do note that
SelectedItem is of type object, so you have to cast it to Employee before treating it as an Employee.
Now step 3: list removal. The ListBox has an
Items property that represents all of the items in the list. This collection has a
Remove() method that lets you remove an item. When the "Remove" button is clicked, we want to remove the selected item. We already know how to get the selected item (and that there might not be one), so all we have to add is a call to
Remove():
Code:
private void btnRemove_Click(object sender, EventArgs e)
{
Employee selectedEmployee = (Employee)lstEmployees.SelectedItem;
if (selectedEmployee != null)
{
lstEmployees.Items.Remove(selectedEmployee);
}
}
Ta da!
Remove() is smart enough to know how to fill in the hole left by the deleted item, so it's done for you. This actually clears the selection in the ListBox; in a professional application you'd set the selection to another item; I omitted this because it's slightly complicated.
You *can* use an array or a list of items in conjunction with a ListBox. My first years of VB .NET were spent writing code this way, because it's how things worked in VB6 and how people taught me to do it in VB .NET. When I stumbled upon the fact that you can make the ListBox the list itself, my applications got *much* simpler because I quit having to write synchronization code. In theory, data binding is supposed to make things easier, but that was just a dream until WPF got data binding right. I'm not walking through a WPF solution.
I'm not trying to usurp or discredit Iceplug's comments so far. I've noticed that we tend to want to teach beginners the lowest-level technique of doing something (I do this a lot too.) I was taught to use arrays for this at first, and it led to tons of extra code and time spent debugging minor synchronization errors. The problem is we're seeing things from years of experience, and in many cases not understanding arrays leads to not understanding other, more advanced concepts. If I didn't understand how arrays work, I wouldn't know so much about how lists work. So we teach arrays, and the beginners learn them, and no one remembers to follow up with the "once you know arrays, you should take advantage of this..." version of the story. It took me 2 years to figure out that a ListBox *is* an array. You just learned it in a week.
