WPF ItemsSource not updating when items added to ObservableCollection?

Let's say our WPF application has an ItemsControl whose ItemsSource is bound to an ObservableCollection. {{< highlight python >}} <UserControl.Resources> </UserControl.Resources> Looks like this document doesn't contain any questionnaire items. {{< / highlight >}}

The Visibility property of the ItemsControl is bound to a custom IValueConverter that returns Visibility.Visible if the ItemsSource is non-empty, or Visibility.Collapsed if empty. Additionally, we have a TextBox with a reverse IValueConverter

In other words, if our ObservableCollection is empty, we display the TextBox to notify the user there's nothing there, otherwise we show the ItemsControl.

If everything goes to plan, on first load, on first load, we should see our "empty" message.


So far so good.

Now if we add an item to the ObservableCollection, the ItemsControl should update and we should see our newly added object.


No bueno - the UI isn't updating; seemingly nothing has been added.

If we step through the debugger, though, we can verify that everything is wired up correctly. The item is definitely added to the collection.


So what's going on?

The key here is the Visibility binding:

{{< highlight python >}} Looks like this document doesn't contain any questionnaire items. {{< / highlight >}}

If we remove this, suddenly everything clicks!


The logic is pretty straightforward - feel free to kick yourself like I did when I figured it out. ObservableCollection raises a CollectionChanged event whenever an item is added or removed - the ItemsSource binding will listen for this event and refresh appropriately.

The Visibility binding, however, will only listen to PropertyChanged event, which is not raised when the collection changes.

This means that, although the ItemsControl itself is being updated, its Visibility (and the Visibility of the overlayed TextBlock) are not.

A simple solution is to add an event handler to the CollectionChanged event on the ObservableCollection:

{{< highlight csharp >}} Items.CollectionChanged += Items_CollectionChanged;

private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { NotifyPropertyChanged("Items"); } {{< / highlight >}}

This will then refresh the Visibility bindings whenever the ObservableCollection changes, ensuring the updated ItemsControl is actually visible.

Depending on the size of the collection, this may be quite resource-intensive, so YMMV.