Reputation: 23394
When I change a property in an item in a BindingList, the changes do not propagate to the ListBox although the underlying object is changed.
public class MyClass : INotifyPropertyChanged
{
public override string ToString()
{
return this.Name;
}
#region Name
private string name;
public string Name
{
get
{
return this.name;
}
set
{
if (value == this.name) return;
this.name = value;
this.OnPropertyChanged("Name");
}
}
#endregion
#region INotifyPropertyChanged event
///<summary>
///Occurs when a property value changes.
///</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the <see cref="PropertyChanged"/> event for
/// a given property.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
protected void OnPropertyChanged(string propertyName)
{
//validate the property name in debug builds
VerifyProperty(propertyName);
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Verifies whether the current class provides a property with a given
/// name. This method is only invoked in debug builds, and results in
/// a runtime exception if the <see cref="OnPropertyChanged"/> method
/// is being invoked with an invalid property name. This may happen if
/// a property's name was changed but not the parameter of the property's
/// invocation of <see cref="OnPropertyChanged"/>.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
[Conditional("DEBUG")]
private void VerifyProperty(string propertyName)
{
Type type = this.GetType();
//look for a *public* property with the specified name
PropertyInfo pi = type.GetProperty(propertyName);
if (pi == null)
{
//there is no matching property - notify the developer
string msg = "OnPropertyChanged was invoked with invalid property name {0}: ";
msg += "{0} is not a public property of {1}.";
msg = String.Format(msg, propertyName, type.FullName);
Debug.Fail(msg);
}
}
#endregion
}
and the XAML
<Window x:Class="testBL.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ListBox x:Name="myListBox">
</ListBox>
<Button x:Name="changeButton" Click="changeButton_Click">Change an item</Button>
</StackPanel>
</Window>
Upvotes: 0
Views: 1240
Reputation: 34250
Because you are binding the ListBox
to the collection, the default data context for each ListBoxItem
is the instance. The collection for example is an ObservableCollection<MyClass>
and the data context for each ListBoxItem
is a MyClass
instance.
Since you haven't provided a data template, the ListBoxItem
is effectively bound to "{Binding}"
which results in your MyClass.ToString()
method being called. Since ToString()
isn't a property, it doesn't support property change notification. Using binding in this way (binding to ToString()
), only works for immutable objects.
The solution is to provide an explicit binding for your ListBoxItem
like this:
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
or to make your MyClass
object immutable and replace them instead of mutating them.
Upvotes: 1
Reputation: 11230
You need to assign an event handler each item in the BindingList's NotifyPropertyChanged, and when that occurs, in the event handler raise a CollectionChanged event.
I would recommend using a collection that inherits from ObservableCollection and automatically assigns and removes the handlers. I call this a VeryObservableCollection.
Upvotes: 0