Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListBox item not updated when property changed

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

like image 537
Abdul Avatar asked Mar 13 '13 21:03

Abdul


3 Answers

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; }
}
like image 111
sa_ddam213 Avatar answered Oct 16 '22 08:10

sa_ddam213


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" />
like image 5
Jehof Avatar answered Oct 16 '22 06:10

Jehof


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

like image 4
WiiMaxx Avatar answered Oct 16 '22 07:10

WiiMaxx