C# tutorials > Core C# Fundamentals > Data Structures and Collections > What are observable collections (`ObservableCollection<T>`)?

What are observable collections (`ObservableCollection<T>`)?

Understanding Observable Collections in C#

Observable collections (`ObservableCollection `) are dynamic data collections in C# that automatically notify listeners when items are added, removed, changed, or when the entire collection is refreshed. This makes them particularly useful in scenarios where the UI needs to be kept synchronized with the underlying data, such as in WPF, UWP, and .NET MAUI applications. They implement the `INotifyCollectionChanged` interface.

Basic Concept and Implementation

This code demonstrates a basic implementation of `ObservableCollection`. The `CollectionChanged` event is subscribed to, allowing the application to respond to changes in the collection. The event handler checks the type of change (`Add`, `Remove`, `Replace`, or `Reset`) and performs actions accordingly. The `AddName`, `RemoveName`, `ReplaceName` and `Reset` methods are provided to modify the collection and trigger the `CollectionChanged` event.

using System.Collections.ObjectModel;

public class Example
{
    public ObservableCollection<string> Names { get; set; }

    public Example()
    {
        Names = new ObservableCollection<string>();
        Names.CollectionChanged += Names_CollectionChanged;
    }

    private void Names_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                if (e.NewItems != null)
                {
                    foreach (var item in e.NewItems)
                    {
                        Console.WriteLine($"Added: {item}");
                    }
                }
                break;
            case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                if (e.OldItems != null)
                {
                    foreach (var item in e.OldItems)
                    {
                        Console.WriteLine($"Removed: {item}");
                    }
                }
                break;
            case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                if (e.OldItems != null && e.NewItems != null)
                {
                    Console.WriteLine($"Replaced {e.OldItems[0]} with {e.NewItems[0]}");
                }
                break;
            case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                Console.WriteLine("Collection was reset");
                break;
        }
    }

    public void AddName(string name)
    {
        Names.Add(name);
    }

    public void RemoveName(string name)
    {
        Names.Remove(name);
    }

    public void ReplaceName(string oldName, string newName)
    {
        int index = Names.IndexOf(oldName);
        if (index != -1)
        {
            Names[index] = newName;
        }
    }

    public void Reset()
    {
        Names.Clear();
    }
}

Concepts Behind the Snippet

The core concept behind `ObservableCollection` is the observer pattern. It allows objects (in this case, UI elements) to subscribe to changes in the collection. When the collection is modified, it notifies all subscribers. The `INotifyCollectionChanged` interface is key to this behavior. Any change to the collection triggers the `CollectionChanged` event, which then notifies the subscribers. The `NotifyCollectionChangedEventArgs` provides information about the type of change that occurred, as well as the affected items (if any).

Real-Life Use Case

In a WPF application, you might bind a `ListBox` to an `ObservableCollection` of names. When you add a new name to the collection, the `ListBox` will automatically update to display the new name without requiring any manual UI refresh. This is incredibly useful for creating responsive and data-driven user interfaces.

<!-- XAML Example -->
<ListBox ItemsSource="{Binding Names}" />

// C# ViewModel
public class ViewModel : INotifyPropertyChanged
{
    private ObservableCollection<string> _names = new ObservableCollection<string>();
    public ObservableCollection<string> Names
    {
        get { return _names; }
        set
        {
            _names = value;
            OnPropertyChanged(nameof(Names));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ViewModel()
    {
        Names.Add("Alice");
        Names.Add("Bob");
    }
}

Best Practices

  • Thread Safety: `ObservableCollection` is not inherently thread-safe. If you are modifying the collection from multiple threads, you need to implement proper synchronization mechanisms (e.g., using `lock` statements or the `Dispatcher` in WPF).
  • Minimize UI Updates: Avoid making frequent, small changes to the collection, as each change will trigger a UI update. Batch changes together when possible.
  • Use with MVVM: `ObservableCollection` is a cornerstone of the Model-View-ViewModel (MVVM) pattern. Use it to expose data from your view models to your views.
  • Careful with complex objects If you are observing collections of complex objects, make sure those objects implement `INotifyPropertyChanged` to reflect property changes within the objects themselves.

Interview Tip

When asked about `ObservableCollection`, be prepared to discuss its role in data binding, the `INotifyCollectionChanged` interface, and its use in MVVM applications. Also, be ready to explain thread safety considerations and best practices for using it effectively.

When to Use Them

Use `ObservableCollection` when you need to keep a UI automatically synchronized with a data collection. This is particularly important in data-driven applications where the data is frequently changing. Avoid using them in scenarios where performance is critical and UI updates are not required, as the overhead of the change notifications can be significant. If you need a read-only bindable collection, consider using `ReadOnlyObservableCollection`.

Memory Footprint

The memory footprint of an `ObservableCollection` is similar to that of a `List`, plus the overhead of storing the event handlers for the `CollectionChanged` event. This overhead is generally small, but if you have a large number of observable collections, or if your event handlers are very complex, it could become a factor.

Alternatives

  • `List`: If you don't need change notifications, `List` is a more performant option. You can manually update the UI when the list changes.
  • `BindingList`: An alternative that provides change notifications, can raise change events for object properties if the objects implement `INotifyPropertyChanged`, and it supports sorting and filtering.
  • Custom Observable Collections: You can implement your own observable collection if you need more control over the change notification process or if you need to support specific scenarios that `ObservableCollection` doesn't handle.

Pros

  • Automatic UI Updates: Simplifies UI development by automatically synchronizing the UI with the underlying data.
  • MVVM Friendly: Integrates seamlessly with the MVVM pattern.
  • Easy to Use: Relatively simple to implement and use.

Cons

  • Performance Overhead: Change notifications can add overhead, especially for large collections or frequent changes.
  • Not Thread-Safe: Requires manual synchronization when used from multiple threads.
  • Can be Overkill: Unnecessary if change notifications are not required.

FAQ

  • Is `ObservableCollection` thread-safe?

    No, `ObservableCollection` is not inherently thread-safe. You need to implement your own synchronization mechanisms (e.g., using `lock` statements) if you are modifying the collection from multiple threads.
  • What is the difference between `ObservableCollection` and `List`?

    `ObservableCollection` implements the `INotifyCollectionChanged` interface, which allows it to notify listeners (e.g., UI elements) when the collection changes. `List` does not have this functionality. If you need automatic UI updates, use `ObservableCollection`. If not, `List` is generally more performant.
  • How do I handle property changes within objects in an ObservableCollection?

    The objects within the `ObservableCollection` should implement `INotifyPropertyChanged`. When a property changes on one of these objects, it raises the `PropertyChanged` event. You can then subscribe to this event to update the UI accordingly.