Reputation: 1005
I need to make list of items. I binded collection of users to listbox. Everything works quite well, but items in listbox aren't updated in real time. They aren't updated at all by this binding. So when I remove any user from the list, listbox isn't updated even if its source is correctly changed.
Source is located in data view model at path DataViewModel.Instance.AllUsers; Whenever I add to this list new item or remove one, layout does not update. Other bindings work well. I tried to update listbox layout, to raise event of source update, other way of adding/removing items, but nothing worked.
I tried to debug binding, but I have too many bindings to find the error.
Thanks in advance for any useful advice.
Listbox:
<ListBox x:Name="ListboxUsers" ItemsSource="{Binding Path=AllUsers, Mode=OneWay}" Grid.Column="1" Margin="0" Grid.Row="5" Background="DimGray" BorderThickness="0" Visibility="Hidden" SelectionChanged="ListboxUsers_SelectionChanged"/>
Code-behind:
CatalogueGrid.DataContext = DataViewModel.Instance; //whole view model added as datacontext
DataViewModel class:
public class DataViewModel : INotifyPropertyChanged
{
private static DataViewModel _dataViewModel;
private Collection<UserModel> allUsers;
public Collection<UserModel> AllUsers
{
get
{
return allUsers;
}
set
{
allUsers = value;
NotifyPropertyChanged("AllUsers");
}
}
private DataViewModel()
{
AllUsers = new Collection<UserModel>();
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
.
.
.
}
Upvotes: 4
Views: 10247
Reputation: 9944
use ObservableColLection
instead if Collection
wich implements the INotifyCollectionChanged
Interface :
private ObservableCollection<UserModel> allUsers;
public ObservableCollection<UserModel> AllUsers
{
get
{
return allUsers;
}
set
{
allUsers = value;
NotifyPropertyChanged("AllUsers");
}
}
Upvotes: 12
Reputation: 20731
You have bound your listbox to a Collection<T>
- that is just a list, which does not issue any notifications to bound properties that its contents has changed. Hence, your listbox cannot possibly know when the collection has changed.
Instead, you can use the ObservableCollection<T>
class (or, more precisely, any collection that also implements INotifyCollectionChanged
), and changes will be automatically propagated to the listbox.
Note that your property does not have to be typed as ObservableCollection<T>
, you can also just declare your public property as IEnumerable<T>
or IList<T>
; the binding will find out on its own whether the returned class also implements INotifyCollectionChanged
. Like this, you are free to replace your actual underlying collection class later on, for example with a ReadOnlyObservableCollection<T>
, in case you want to disallow changes from the outside.
Speaking of this, a note on your code: You have provided your AllUsers
property with a setter. This may lead to undesired consequences, as you open up possibilities for some other code to set the property to null
, which (depending on the rest of your code) might lead to exceptions. Unless you actually want to allow assigning new values, for the ItemsSource
property binding, a read-only property is fully sufficient, as long as the returned collection object implements INotifyCollectionChanged
.
Upvotes: 3
Reputation: 61349
For changes to the collection to propagate to the UI, the collection class needs to implement INotifyCollectionChanged
.
A very useful class that already implements this is ObservableCollection<T>
(MSDN). Use that instead of Collection<T>
.
Upvotes: 5