Question

I am trying to make an application that binds a List/Collection etc of custom objects (Places) with a listbox so that:

  • ListBox displays a selected property ("name") of every object
  • Selecting an item in ListBox changes the "current" item in List/Collection
  • Adding/Removing an item in ListBox, adds/removes an item in List/Collection
  • Adding/Removing an item in List/Collection, adds/removes an item in ListBox
  • Changing the displayed property of an item, changes the item in ListBox

My code so far is:

namespace DataBindingTest

{

public partial class Form1 : Form

{

    BindingSource bs;
    ObservableCollection<Place> places = new ObservableCollection<Place>();
    Place place1 = new Place("pl1", 2.2);
    Place place2 = new Place("pl2", 2.3);

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        bs = new BindingSource();
        places.Add(place1);
        places.Add(place2);
        bs.DataSource = places;

        listBox1.DataSource = bs;
        listBox1.DisplayMember = "Name";
        listBox1.DataBindings.Add(new Binding("Text", bs, "Name", true, DataSourceUpdateMode.OnPropertyChanged));             
    }

    public class Place : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        string name;
        double losses;

        public Place(string n, double l)
        {
            name = n;
            losses = l;
        }

        public string Name
        {
            get { return name; }
            set 
            {
                name = value;
                OnPropertyChanged("Name");
            }
        }

        public double Losses
        {
            get { return losses; }
            set { losses = value; }
        }

        protected void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {

        places[0].Name = "Place 1";
        places[1].Name = "Place 2";
    }
}

When OnPropertyChanged is called for places[0] it's OK, when it's called for places[1], the handler is null! Why is that happening?

SOLUTION

It seems to be a problem (bug maybe?) with ObservableCollection! If I use BindingList instead, it works fine!! Found it here. after 3 days of searching.

EDIT

namespace DataBindingTest
{
    public partial class Form1 : Form
    {
        BindingSource bs;
        BindingList<Place> places = new BindingList<Place>();
        Place place1 = new Place("pl1", 2.2);
        Place place2 = new Place("pl2", 2.3);


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            bs = new BindingSource();
            places.Add(place1);
            places.Add(place2);
            bs.DataSource = places;

            listBox1.DataSource = bs;
            listBox1.DisplayMember = "Name";
            listBox1.DataBindings.Add(new Binding("Text", bs, "Name", true, DataSourceUpdateMode.OnPropertyChanged));

            Place place3 = new Place("pl3", 0);
            bs.Add(place3);
            places[2].Name = "Place3";

        }

        private void button1_Click(object sender, EventArgs e)
        {
            places[0].Name = "Place 1";
            places[1].Name = "Place 2";
        }


    }


    public class Place : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        string name;
        double losses;

        public Place(string n, double l)
        {
            name = n;
            losses = l;
        }


        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged("Name");

            }
        }

        public double Losses
        {
            get { return losses; }
            set { losses = value; }
        }

        protected void OnPropertyChanged(string PropertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(PropertyName));
        }
    }

}

I just put the Class Place outside the Class Form1, because I need to use it in the whole namespase, but I dont think it changes something.

Was it helpful?

Solution

It seems to be a problem (bug maybe?) with ObservableCollection! If I use BindingList instead, it works fine!! Found it here. after 3 days of searching.

EDIT

namespace DataBindingTest 
{

    public partial class Form1 : Form

    {

        BindingSource bs;
        BindingList<Place> places = new BindingList<Place>();
        Place place1 = new Place("pl1", 2.2);
        Place place2 = new Place("pl2", 2.3);


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            bs = new BindingSource();
            places.Add(place1);
            places.Add(place2);
            bs.DataSource = places;

            listBox1.DataSource = bs;
            listBox1.DisplayMember = "Name";
            listBox1.DataBindings.Add(new Binding("Text", bs, "Name", true, DataSourceUpdateMode.OnPropertyChanged));

            Place place3 = new Place("pl3", 0);
            bs.Add(place3);
            places[2].Name = "Place3";

        }

        private void button1_Click(object sender, EventArgs e)
        {
            places[0].Name = "Place 1";
            places[1].Name = "Place 2";
        }


    }


    public class Place : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        string name;
        double losses;

        public Place(string n, double l)
        {
            name = n;
            losses = l;
        }


        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged("Name");

            }
        }

        public double Losses
        {
            get { return losses; }
            set { losses = value; }
        }

        protected void OnPropertyChanged(string PropertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(PropertyName));
        }
    }

}

OTHER TIPS

Not sure why, but it only seems to update the selected item. This isn't elegant, but it does seem to work as a stopgap solution:

private void button1_Click(object sender, EventArgs e)
{
   int actualIndex = listBox1.SelectedIndex;
   listBox1.SelectedIndex = 0;
   places[0].Name = "Place 1";
   listBox1.SelectedIndex = 1;
   places[1].Name = "Place 2";
   listBox1.SelectedIndex = actualIndex;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top