I am trying to bind a list box to a collection. The problem is that the collection can change, but the collection doesn't implement IObservableCollection. What is the best way to force the binding to refresh?
Without more information on how and where this collection is used, here are some pointers which may help you.
- If the collection is not sealed, you could inherit it.
- If the collection is sealed, you could create an adapter class which contains an instance of your collection and wraps all relevant methods.
In any case, your new class could implement IObservableCollection
and be used for binding.
As Tormod suggested, the preferable methods would be changing the collection to an ObservableCollection, or implementing INotifyCollectionChanged in the collection would take care of refreshing the UI.
However, if those options aren't available, then you can 'force' a refresh by using INotifyPropertyChanged in whatever class contains the collection. We then will be treating the list just like a regular property, and using the setter to notify on changes. To do this it requires re-assigning the reference, which is why using something like an ObservableCollection is preferred, as well as raising the PropertyChanged event.
Here is a quick sample showing how this can be done with just a standard generic List:
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
this.Names = new List<string>() { "Mike", "Robert" };
this.DataContext = this;
}
private IList<string> myNames;
public IList<string> Names
{
get
{
return this.myNames;
}
set
{
this.myNames = value;
this.NotifyPropertyChanged("Names");
}
}
private void OnAddName(object sender, RoutedEventArgs e)
{
Names.Add("Kevin");
Names = Names.ToList();
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Xaml:
<Window x:Class="Sample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300">
<Grid>
<StackPanel>
<ListBox ItemsSource="{Binding Names}" />
<Button Content="Add Name"
Click="OnAddName" />
</StackPanel>
</Grid>
You can set a binding to update explicitly and then trigger an update through code by say having a refresh button for example.
As an example.
<StackPanel>
<ListBox
x:Name="lb"
ItemsSource="{Binding SomeList, UpdateSourceTrigger=Explicit}"
/>
<Button Content="Refresh" Click="Refresh_Click" />
</StackPanel>
private void Refresh_Click(object sender, RoutedEventArgs e)
{
BindingExpression be = lb.GetBindingExpression(ListBox.ItemsSourceProperty);
be.UpdateSource();
}
You can also force a refresh in your ViewModel. This is sth I've seen Josh Smith do in his MVVM demo app:
ICollectionView coll = CollectionViewSource.GetDefaultView(myCollection);
if (coll!=null)
coll.Refresh();
myCollection can be any type of collection that you have bound to the View.
Bea Stollnitz has a bit more information about CollectionViewSource: http://www.beacosta.com/blog/?m=200608