DispatchingObservableCollection.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.Diagnostics;
  6. using System.Windows.Threading;
  7. using System.Collections.Specialized;
  8. using System.ComponentModel;
  9. namespace TsViewer
  10. {
  11. /// <summary>
  12. /// ObservableCollection that automatically calls event handlers via the target object's Dispatcher if available.
  13. /// Targets that don't derive from DispatcherObject are called on the same thread that the event is invoked from.
  14. ///
  15. /// Author: Jason S. Clary
  16. /// </summary>
  17. /// <typeparam name="T">The type of the elements</typeparam>
  18. public class DispatchingObservableCollection<T> : ObservableCollection<T>
  19. {
  20. private readonly EventHandlerList _delegates = new EventHandlerList();
  21. private readonly Dictionary<Dispatcher, EventHandlerList> _dispatcherDelegates =
  22. new Dictionary<Dispatcher, EventHandlerList>();
  23. public DispatchingObservableCollection() { }
  24. public DispatchingObservableCollection(IEnumerable<T> collection) : base(collection) { }
  25. private readonly object _collectionChanged = new Object();
  26. public override event NotifyCollectionChangedEventHandler CollectionChanged
  27. {
  28. add { AddEventHandler(_collectionChanged, value); }
  29. remove { RemoveEventHandler(_collectionChanged, value); }
  30. }
  31. private readonly object _propertyChanged = new Object();
  32. protected override event PropertyChangedEventHandler PropertyChanged
  33. {
  34. add { AddEventHandler(_propertyChanged, value); }
  35. remove { RemoveEventHandler(_propertyChanged, value); }
  36. }
  37. protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
  38. {
  39. var threadAgnosticDelegates = (NotifyCollectionChangedEventHandler)_delegates[_collectionChanged];
  40. if (threadAgnosticDelegates != null) threadAgnosticDelegates(this, e);
  41. foreach (var dispatcherDelegatePair in _dispatcherDelegates)
  42. {
  43. var eventHandler =
  44. (NotifyCollectionChangedEventHandler)dispatcherDelegatePair.Value[_collectionChanged];
  45. if (eventHandler == null) continue;
  46. if (dispatcherDelegatePair.Key.CheckAccess())
  47. eventHandler(this, e);
  48. else
  49. dispatcherDelegatePair.Key.BeginInvoke(DispatcherPriority.DataBind, new Action(() => eventHandler(this, e)));
  50. }
  51. }
  52. protected override void OnPropertyChanged(PropertyChangedEventArgs e)
  53. {
  54. var threadAgnosticDelegates = (PropertyChangedEventHandler)_delegates[_propertyChanged];
  55. if (threadAgnosticDelegates != null) threadAgnosticDelegates(this, e);
  56. foreach (var dispatcherDelegatePair in _dispatcherDelegates)
  57. {
  58. var eventHandler =
  59. (PropertyChangedEventHandler)dispatcherDelegatePair.Value[_propertyChanged];
  60. if (eventHandler == null) continue;
  61. if (dispatcherDelegatePair.Key.CheckAccess())
  62. eventHandler(this, e);
  63. else
  64. dispatcherDelegatePair.Key.BeginInvoke(DispatcherPriority.DataBind, new Action(() => eventHandler(this, e)));
  65. }
  66. }
  67. private void AddEventHandler(object eventObject, Delegate handler)
  68. {
  69. var target = handler.Target as DispatcherObject;
  70. if (target != null)
  71. {
  72. EventHandlerList eventHandlerList;
  73. if (!_dispatcherDelegates.TryGetValue(target.Dispatcher, out eventHandlerList))
  74. {
  75. eventHandlerList = new EventHandlerList();
  76. _dispatcherDelegates.Add(target.Dispatcher, eventHandlerList);
  77. }
  78. eventHandlerList.AddHandler(eventObject, handler);
  79. }
  80. else
  81. _delegates.AddHandler(eventObject, handler);
  82. }
  83. private void RemoveEventHandler(object eventObject, Delegate handler)
  84. {
  85. var target = handler.Target as DispatcherObject;
  86. if (target != null)
  87. {
  88. EventHandlerList eventHandlerList;
  89. if (!_dispatcherDelegates.TryGetValue(target.Dispatcher, out eventHandlerList))
  90. {
  91. eventHandlerList = new EventHandlerList();
  92. _dispatcherDelegates.Add(target.Dispatcher, eventHandlerList);
  93. }
  94. eventHandlerList.RemoveHandler(eventObject, handler);
  95. }
  96. else
  97. _delegates.RemoveHandler(eventObject, handler);
  98. }
  99. }
  100. }