From StackOverflow searches, I see that there are two possible ways: use an implementation of a TrulyObservableCollection; or use a Binding List.
StackOverflow resource:
In your console application first implement a property that implements INotifyPropertyChanged for you:
ViewModelBase.cs
using System.ComponentModel;
namespace ObservableCollection
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Code samples as follows:
1. TrulyObservableCollection
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
namespace ObservableCollection
{
public class Item : ViewModelBase
{
private string _value;
public string Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged("Value");
}
}
}
public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
where T : INotifyPropertyChanged
{
private TrulyObservableCollection()
{
CollectionChanged += FullObservableCollectionCollectionChanged;
}
public TrulyObservableCollection(IEnumerable<T> pItems) : this()
{
foreach (var item in pItems)
Add(item);
}
private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach (var item in e.NewItems)
((INotifyPropertyChanged) item).PropertyChanged += ItemPropertyChanged;
if (e.OldItems == null) return;
{
foreach (var item in e.OldItems)
((INotifyPropertyChanged) item).PropertyChanged -= ItemPropertyChanged;
}
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender,
IndexOf((T) sender));
OnCollectionChanged(args);
}
}
internal static class Program
{
private static void Main(string[] args)
{
var items = new List<Item>
{
new Item {Value = "1"},
new Item {Value = "2"}
};
var list = new TrulyObservableCollection<Item>(items);
list.CollectionChanged += OnCollectionChanged;
// Change one of the value in the truly observable collection
list[0].Value = "3";
}
private static void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Event raised.
// Now do your stuff...
Console.WriteLine("Item in the collection has been changed, handling this event.");
}
}
}
Giving the following output as soon as one of the items in the observable collection is changed:
2. BindingList
Quite a bit simpler than creating your own.
BindingList will automatically forward your property’s PropertyChanged events as ListChanged events where ListChangedType == ItemChanged
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace ObservableCollection
{
public class Item : ViewModelBase
{
private string _value;
public string Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged("Value");
}
}
}
internal static class Program
{
private static void Main(string[] args)
{
var items = new List<Item>
{
new Item {Value = "1"},
new Item {Value = "2"}
};
var bindingList = new BindingList<Item> { new Item { Value = "1" } };
bindingList.ListChanged += OnBindingListChanged;
bindingList[0].Value = "3";
// Change one of the value in the bindingList collection
bindingList[0].Value = "3";
}
private static void OnBindingListChanged(object sender, ListChangedEventArgs e)
{
// Event raised.
// Now do your stuff...
Console.WriteLine("Item in the collection has been changed, handling this event.");
}
}
}
Giving the following output:

