Skip to content

Instantly share code, notes, and snippets.

@danielmarbach
Created May 17, 2011 18:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save danielmarbach/977029 to your computer and use it in GitHub Desktop.
Save danielmarbach/977029 to your computer and use it in GitHub Desktop.
Thread safe observable collection
[DebuggerDisplay("Count = {Count}")]
[ComVisible(false)]
public class SafeObservableCollection<T> : ObservableCollection<T>
{
private readonly Dispatcher dispatcher;
public SafeObservableCollection()
: this(Enumerable.Empty<T>())
{
}
public SafeObservableCollection(Dispatcher dispatcher)
: this(Enumerable.Empty<T>(), dispatcher)
{
}
public SafeObservableCollection(IEnumerable<T> collection)
: this(collection, Dispatcher.CurrentDispatcher)
{
}
public SafeObservableCollection(IEnumerable<T> collection, Dispatcher dispatcher)
{
this.dispatcher = dispatcher;
foreach (T item in collection)
{
this.Add(item);
}
}
protected override void SetItem(int index, T item)
{
this.ExecuteOrInvoke(() => this.SetItemBase(index, item));
}
protected override void MoveItem(int oldIndex, int newIndex)
{
this.ExecuteOrInvoke(() => this.MoveItemBase(oldIndex, newIndex));
}
protected override void ClearItems()
{
this.ExecuteOrInvoke(this.ClearItemsBase);
}
protected override void InsertItem(int index, T item)
{
this.ExecuteOrInvoke(() => this.InsertItemBase(index, item));
}
protected override void RemoveItem(int index)
{
this.ExecuteOrInvoke(() => this.RemoveItemBase(index));
}
private void RemoveItemBase(int index)
{
base.RemoveItem(index);
}
private void InsertItemBase(int index, T item)
{
base.InsertItem(index, item);
}
private void ClearItemsBase()
{
base.ClearItems();
}
private void MoveItemBase(int oldIndex, int newIndex)
{
base.MoveItem(oldIndex, newIndex);
}
private void SetItemBase(int index, T item)
{
base.SetItem(index, item);
}
private void ExecuteOrInvoke(Action action)
{
if (this.dispatcher.CheckAccess())
{
action();
}
else
{
this.dispatcher.BeginInvoke(action);
}
}
}
@lummo
Copy link

lummo commented Sep 17, 2012

Might be worth updating this with the BeginInvoke -> Invoke change that Ken listed on your blog:
http://www.planetgeek.ch/2011/05/17/threadsafe-observablecollection/comment-page-1/#comment-1693

@xc6m
Copy link

xc6m commented Mar 3, 2023

Foreachs are not protected, while iterating the collection one can change the collection and the iteration fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment