Frimlik
Frimlik

Reputation: 429

Bind the SelectedItem of a ListBox to another ListBox

I have this model:

class Car
{
  string CrewNickname { get; set; }
  Líst<string> RacersNames { get; set; }
}

class StartingField
{
  List<Car> Cars { get; set; }
}

What I need is to display cars in one ListBox and when I click on any car, to display names of its racers in the second ListBox.
I also need to be able to add/remove cars and add/remove/edit racers.

I haven't found any suitable tutorial or question, but I think this must be possible to create.

Upvotes: 1

Views: 275

Answers (2)

Jimi
Jimi

Reputation: 32223

You can do something like this:

  • Use two BindingSource objects to link each Car in the list to its list of RacersNames
  • Add a Property used to show each Car name in the first ListBox (the CarID Property is there just to show the use of ValueMember)
  • You need public Properties, of course.

BindingSource bsCars = null;
BindingSource bsRacers = null;
StartingField startingField = null;

public class Car
{
    public Car(string carName, int carID) { CarName = carName; CarID = carID; }
    public string CarName { get; }
    public int CarID { get; }
    public List<string> RacersNames { get; set; } = new List<string>();
}

public class StartingField
{
    public List<Car> Cars { get; } = new List<Car>();
}

Then initialize the source of data and set the DataSource of the BindingSource objects and the ListBoxes.
Since the second BindingSource is linked to the RacersNames property of the first BindingSource, when you select a car name in the first ListBox, the second BindingSource will update its content and, as a consequence, the ListBox bound to it will show the list of RacersNames related to the new selection.

Elements can be added or removed from both lists.

You can add this code to the Load event (or OnLoad() override) of a Form.

protected override void OnLoad(EventArgs e) 
{
    startingField = new StartingField();
    var c1 = new Car("Car1", 1) { RacersNames = { "Racer1", "Racer2", "Racer3" } };
    var c2 = new Car("Car2", 2) { RacersNames = { "Racer4", "Racer5", "Racer6" } };
    var c3 = new Car("Car3", 3) { RacersNames = { "Racer7", "Racer8", "Racer9" } };
   
    startingField.Cars.AddRange(new[] { c1, c2, c3});

    bsCars = new BindingSource(startingField.Cars, "");
    bsRacers = new BindingSource(bsCars, "RacersNames");

    lstCars.DisplayMember = "CarName";
    lstCars.ValueMember = "CarID";
    lstCars.DataSource = bsCars;
    lstRacers.DataSource = bsRacers;
}

To add or remove Car objects, or add/remove elements from the current RacersNames list, use the linked BindingSources.
You can add/remove elements from the underlying BindingList (the list created internally).

See the animation to determine what Buttons this code maps to

private void btnAddCar_Click(object sender, EventArgs e)
{
    var newCar = startingField.Cars.Count + 1;
    bsCars.Add(new Car($"Car{newCar}", newCar)
    {
        RacersNames = { "Racer10", "Racer11", "Racer12" }
    });
}

private void btnAddRider_Click(object sender, EventArgs e)
{
    bsRacers.Add("New Rider");
}

private void btnRemoveRider_Click(object sender, EventArgs e)
{
    if (lstRacers.SelectedIndex < 0) return;
    bsRacers.Remove(lstRacers.GetItemText(lstRacers.SelectedItem));
}

This is how it works:

BindingSource Linked ListBoxES

Upvotes: 2

payam
payam

Reputation: 41

You should use the OnSelectedIndex method for the first listbox, that raises the SelectedValueChanged event. Then populate the second listbox based on the selected index of the first listbox.

Upvotes: 0

Related Questions