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.