using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Threading; namespace Tango.Core { public static class SynchronizedObservableCollectionConfig { public static bool DisableSynchronization { get; set; } } public class SynchronizedObservableCollection : ObservableCollection { private object _sync_lock = new object(); private object _modify_lock = new object(); private SynchronizedObservableCollectionDispatcher _dispatcher; public bool DisableSynchronization { get; set; } = SynchronizedObservableCollectionConfig.DisableSynchronization; public SynchronizedObservableCollection() : base() { if (!DisableSynchronization) { _dispatcher = new SynchronizedObservableCollectionDispatcher(); BindingOperations.EnableCollectionSynchronization(this, _modify_lock); } } public SynchronizedObservableCollection(IEnumerable collection) : base(collection) { if (!DisableSynchronization) { _dispatcher = new SynchronizedObservableCollectionDispatcher(); BindingOperations.EnableCollectionSynchronization(this, _modify_lock); } } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (!DisableSynchronization) { lock (_modify_lock) { _dispatcher.Invoke(() => { base.OnCollectionChanged(e); }); } } else { base.OnCollectionChanged(e); } } protected override void InsertItem(int index, T item) { if (!DisableSynchronization) { lock (_modify_lock) { base.InsertItem(index, item); } } else { base.InsertItem(index, item); } } protected override void RemoveItem(int index) { if (!DisableSynchronization) { lock (_modify_lock) { base.RemoveItem(index); } } else { base.RemoveItem(index); } } protected override void ClearItems() { if (!DisableSynchronization) { lock (_modify_lock) { base.ClearItems(); } } else { base.ClearItems(); } } } internal class SynchronizedObservableCollectionDispatcher { internal Dispatcher Dispatcher { get; set; } internal SynchronizedObservableCollectionDispatcher() { if (Application.Current != null) { Dispatcher = Application.Current.Dispatcher; } } internal void Invoke(Action action) { if (Dispatcher != null) { Dispatcher.Invoke(action); } else { action(); } } } }