I have problem updating Listbox containing ObservableCollection when property of collection changes (adding/removing items from list works fine):
listbox has set ItemsSource="{Binding Path=AllPerson}"
and data context in code behind is set like this this.DataContext = allPersonClass;
.
allPersonClass
contains ObservableCollection<Person> allPerson
Class Person
contains properties like Name etc.
I've overwritten person's ToString
method to return Name
property so listBox shows valid data
I've tried to make Person
implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(object sender, string propertyName) {
if (this.PropertyChanged != null) {
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}
public string Name {
get { return name; }
set {
name = value;
onPropertyChanged(this, "allPersonClass");
}
}
and in every property setter has onPropertyChanged(this, "propertyName");
which is executed but listBox never updates already created item
Any idea what might be wrong?
here is window with listBox xaml
<Button x:Name="btnDetail" Content="Detail" HorizontalAlignment="Left" Margin="361,249,0,0" VerticalAlignment="Top" Width="75" Click="ButtonDetailClick"/>
<ListBox x:Name="listPerson" ItemsSource="{Binding Path=AllPerson}" HorizontalAlignment="Left" Height="170" Margin="33,29,0,0" VerticalAlignment="Top" Width="155" IsSynchronizedWithCurrentItem="True"/>
<Button x:Name="btnLoad" Content="Load" HorizontalAlignment="Left" Margin="58,249,0,0" VerticalAlignment="Top" Width="75" Click="btnLoad_Click"/>
<Button x:Name="btnSave" Content="Save" HorizontalAlignment="Left" Margin="138,249,0,0" VerticalAlignment="Top" Width="75" Click="ButtonSaveClick"/>
this is part of DetailView window where modifications are made (binded to Person)
<TextBox Text="{Binding Path=Name}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />
here is part AllPersonClass:
public class AllPersonClass {
private ObservableCollection<Person> allPerson;
public AllPersonClass() {
allPerson = new ObservableCollection<Person>();
}
public ObservableCollection<Person> AllPerson {
get { return allPerson; }
set { allPerson = value; }
}
public void addPerson(Person newPerson) {
allPerson.Add(newPerson);
}
public Person getPerson(int personIndex) {
return allPerson[personIndex];
}
}
EDIT
here is relevant part of method to save changes in detail view
private void OnBtnSaveClick(object sender, RoutedEventArgs e) {
person.Name = txtName.Text;
person.SurName = txtSurName.Text;
}
note that changes are made in ´ObservableCollection allPerson´ only listBox keeps showing old data
If you want the UI to update when you make changes to Person properties you have to notifiy that that property has changed, not the class
public string Name
{
get { return name; }
set
{
name = value;
onPropertyChanged(this, "allPersonClass");
}
}
<TextBox Text="{Binding Path=Name}" .....
Should be
public string Name
{
get { return name; }
set
{
name = value;
onPropertyChanged(this, "Name");
}
}
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" .....
And you dont have to override ToString()
on the Person
model to show correctly in your ListBox
, you can set the ListBox
DisplayMemberPath
to show the property you want in the ListBox
<ListBox ItemsSource="{Binding Path=AllPerson}" DisplayMemberPath="Name" />
Edit: to answer your comment question:
public string Name
{
get { return name; }
set
{
name = value;
onPropertyChanged(this, "Name");
onPropertyChanged(this, "Display");
}
}
public string Surname
{
get { return surname; }
set
{
surname= value;
onPropertyChanged(this, "Surname");
onPropertyChanged(this, "Display");
}
}
public string Display
{
get { return Name + " " + Surname; }
}
In your DetailView you need to define a TwoWay-Binding to update the Property Name of your person
class.
<TextBox Text="{Binding Path=Name, Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />
Also if you want to update the property every time text is written you also need to define the UpdateSourceTrigger
with PropertyChanged
. Otherwise is the property only update when the TextBox loses focus.
<TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />
your problem is that your collection get never Notifed about your PropertyChanged
this should help you
ObservableCollection<INotifyPropertyChanged> items = new ObservableCollection<INotifyPropertyChanged>();
items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(items_CollectionChanged);
static void items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (INotifyPropertyChanged item in e.OldItems)
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
foreach (INotifyPropertyChanged item in e.NewItems)
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
static void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
see also this Link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With