In this post, you see how to work with ObservableCollection<T> in C#.
In C#, an ObservableCollection<T> is a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. It is the absolute go-to collection in data-binding scenarios (like WPF, MAUI, WinUI, and Blazor) because it automatically keeps the UI in sync with your underlying data.
Here is a complete guide on hoftw to work with it.
Why Use ObservableCollection<T>?If you use a standard List<T> and bind it to a UI element (like a ListView), adding an item to the list won't change what you see on the screen. The UI has no way of knowing the list changed.
ObservableCollection<T> implements the INotifyCollectionChanged interface. Whenever the collection is modified, it fires an event that tells the UI, "Hey, I just changed! Redraw yourself."
Basic Setup and UsageTo use it, you need to import the System.Collections.ObjectModel namespace.
using System.Collections.ObjectModel;
using System.Collections.Specialized;
class Program
{
static void Main()
{
// 1. Initialization
ObservableCollection<string> superheroes = new ObservableCollection<string>()
{
"Batman",
"Superman"
};
// 2. Subscribe to changes (Optional: Usually the UI does this automatically)
superheroes.CollectionChanged += Superheroes_CollectionChanged;
// 3. Modifying the collection triggers the event
superheroes.Add("Wonder Woman");
superheroes.Remove("Superman");
}
// Event handler that fires every time the collection changes
private static void Superheroes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Console.WriteLine($"Collection changed! Action: {e.Action}");
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
Console.WriteLine($"Added: {item}");
}
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
Console.WriteLine($"Removed: {item}");
}
}
} Notes. - In many ways, working with ObservableCollection<T> is identical to working with List<T>, given that both of these classes implement the same core interfaces. What makes the ObservableCollection<T> class unique is that this class supports an event named CollectionChanged. This event will fire whenever a new item is inserted, a current item is removed (or relocated), or the entire collection is modified.
- CollectionChanged event is defined in terms of a delegate, NotifyCollectionChangedEventHandler. This delegate can call any method that takes an object as the first parameter and takes a NotifyCollectionChangedEventArgs as the second.
- The NotifyCollectionChangedEventArgs parameter defines two important properties, OldItems and NewItems, which give you a list of items that were currently in the collection before the event fired and the new items that were involved in the change.
- The NotifyCollectionChangedEventArgs parameter defines Action property, which returns enum type NotifyCollectionChangedAction value (Add = 0, Remove = 1, Replace = 2, Move = 3, Reset = 4).
While ObservableCollection<T> is incredibly useful, it has a few quirks that can trip you up if you aren't careful.
⚠️ Gotcha 1: It only tracks Collection changes, not Property changes
If you modify a property of an item inside the collection, the collection does not fire a notification.
- Triggers UI Update: Add(new User { Name = "Alice" });
- Does NOT Trigger UI Update: myCollection[0].Name = "Bob";
The Fix: The objects inside your collection must implement the INotifyPropertyChanged interface.
⚠️ Gotcha 2: UI Thread Limitations
By default, if you try to modify an ObservableCollection<T> from a background thread while it is data-bound to a UI element, your app will crash with a cross-thread exception.
The Fix: In WPF, you can use BindingOperations.EnableCollectionSynchronization to allow multi-threaded access, or ensure you marshal modifications back to the main thread using something like MainThread.BeginInvokeOnMainThread (in MAUI) or the UI dispatcher.
⚠️ Gotcha 3: Performance with Bulk Updates
If you add 1,000 items to an ObservableCollection<T> using a foreach loop, it will fire the CollectionChanged event 1,000 times. This can cause severe UI stuttering.
The Fix: Create a custom class that inherits from ObservableCollection<T> and implements an AddRange method that suppresses notifications until all items are added:
public class RangeObservableCollection<T> : ObservableCollection<T>
{
public void AddRange(IEnumerable<T> list)
{
// Suppress notification logic or temporarily detach event,
// add items, and fire a single Reset action notification.
foreach (var item in list)
{
this.Items.Add(item);
}
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Summary Comparison
| Feature | List<T> | ObservableCollection<T> |
| Best Used For | Backend logic, data processing, loops | UI Data Binding |
| Performance | Faster (less overhead) | Slower (fires events on changes) |
| Notifies UI on Add/Remove? | No | Yes |
| Notifies UI on Internal Property Change? | No | No (Requires INotifyPropertyChanged on the T item) |
No comments:
Post a Comment