I'm using mvvm-light and I noticed this strange behavior about the RaisePropertyChanged.
xaml:
<ListBox ItemsSource="{Binding Collection}"/>
<TextBlock Text="{Binding Text}"/>
Observable class:
public class A : ObservableObject
{
private string _b;
public string B
{
get { return this._b; }
set
{
this._b = value;
this.RaisePropertyChanged("B");
}
}
}
vm:
public MainViewModel(IDataService dataService) { this.Collection = new List<A>(...); }
public RelayCommand Command1
{
get
{
return this._command1 ?? (this._command1= new RelayCommand(() =>
{
this.Collection.Add(new A());
this.Collection[2].B = "updated";
this.RaisePropertyChanged("Collection");
this.RaisePropertyChanged("Text");
}));
}
}
public RelayCommand Command2
{
get { return this._command2?? (this._command2 = new RelayCommand(() => { this.Text++; })); }
}
public List<A> Collection { get; set; }
public int Text { get; set; }
So, RaisePropertyChanged("Collection") doesn't update the binding while RaisePropertyChanged("Text") do. I can see it by executing the Command2 several times and the Command1 after that. If the Collection is an ObservableCollection then new element shows in a view, but updated item isn't, which means an internal mechanism of an ObservableCollection works, but not the RaisePropertyChanged.
First, an explanation of the issue:
On Windows Phone, when setting a value for a dependency property, the framework internally check if the new value is different from the old one (for optimization purpose maybe). When you raise the PropertyChanged
event or directly re-assign your collection to the ItemsSource
property (which is just a wrapper around the ItemsControl.ItemsSourceProperty
dependency property), the framework detects that the value actually didn't change and doesn't update the property. Therefore, the ListBox
is never notified of your changes, and isn't updated.
The ObservableCollection
works because it uses a whole different mechanism: the ListBox
directly subscribes to the CollectionChanged
event of your collection, and thus isn't hindered by the limitations of the dependency properties.
Now, how to get around this limitation? The only workarounds I can think of are:
ObservableCollection
instead of a List
null
to the ItemsSource
property of your ListBox
, then re-assign your collectionBind the ListBox
to a property that will return a different collection every time it's called:
public List<A> CollectionCopy
{
get
{
return this.Collection.ToList();
}
}