| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 | 
							- using System;
 
- using System.Collections;
 
- using System.Collections.Generic;
 
- using System.Collections.Specialized;
 
- using System.ComponentModel;
 
- using System.Diagnostics;
 
- using System.Runtime.CompilerServices;
 
- using System.Threading;
 
- using System.Threading.Tasks;
 
- using System.Windows;
 
- using System.Windows.Threading;
 
- namespace MECF.Framework.UI.Client.ClientBase.Collections
 
- {
 
-     /// <summary>
 
-     /// The collection is thread-safe.
 
-     /// </summary>
 
-     /// <typeparam name="T"></typeparam>
 
-     public class DelayedPresentRollingObservableCollection<T> : IEnumerable<T>, INotifyCollectionChanged, INotifyPropertyChanged
 
-     {
 
-         #region Variables
 
-         public event NotifyCollectionChangedEventHandler CollectionChanged;
 
-         private readonly List<T> _list;
 
-         private readonly List<T> _cache;
 
-         private readonly object _lockList;
 
-         private readonly object _lockCache;
 
-         private readonly SemaphoreSlim _semListEnumLocker;
 
-         private readonly int _presentDelayMillisec = 200; // the default delay is 200ms
 
-         #endregion
 
-         #region Constructors
 
-         public DelayedPresentRollingObservableCollection(int capacity)
 
-         {
 
-             if (capacity <= 0)
 
-                 throw new ArgumentException("the capacity must be grate than 0.", nameof(capacity));
 
-             _lockList = new object();
 
-             _lockCache = new object();
 
-             _semListEnumLocker = new SemaphoreSlim(0, 1);
 
-             Capacity = capacity;
 
-             lock (_lockList)
 
-             {
 
-                 _list = new List<T>();
 
-             }
 
-             lock (_lockCache)
 
-             {
 
-                 _cache = new List<T>();
 
-             }
 
-             _semListEnumLocker.Release();
 
-             _ = Task.Run(async () =>
 
-             {
 
-                 Thread.Sleep(2000);
 
-                 while (true)
 
-                 {
 
-                     try
 
-                     {
 
-                         Present();
 
-                     }
 
-                     catch (Exception e)
 
-                     {
 
-                         Trace.WriteLine($"Unable to present the items, {e.Message}");
 
-                         Debugger.Break();
 
-                     }
 
-                     finally
 
-                     {
 
-                         // present the data every 200ms
 
-                         await Task.Delay(_presentDelayMillisec);
 
-                     }
 
-                 }
 
-             });
 
-         }
 
-         public DelayedPresentRollingObservableCollection(int capacity, int presentDelayMillisec) : this(capacity)
 
-         {
 
-             _presentDelayMillisec = presentDelayMillisec < 50 ? 50 : presentDelayMillisec;
 
-         }
 
-         #endregion
 
-         #region Properties
 
-         public int Capacity { get; }
 
-         public int Count
 
-         {
 
-             get
 
-             {
 
-                 lock (_lockList)
 
-                 {
 
-                     return _list?.Count ?? 0;
 
-                 }
 
-             }
 
-         }
 
-         #endregion
 
-         #region Methods
 
-         /// <summary>
 
-         /// Copy the items from the cache to the presented list and update the UI.
 
-         /// </summary>
 
-         private void Present()
 
-         {
 
-             var itemsChanged = new List<T>();
 
-             lock (_lockCache)
 
-             {
 
-                 if (_cache.Count <= 0)
 
-                     return;
 
-                 itemsChanged.AddRange(_cache);
 
-                 _cache.Clear();
 
-             }
 
-             var notifyAction = NotifyCollectionChangedAction.Add;
 
-             lock (_lockList)
 
-             {
 
-                 _list.AddRange(itemsChanged);
 
-                 if (_list.Count >= Capacity)
 
-                 {
 
-                     var cntToRemain = Capacity / 2;
 
-                     _list.RemoveRange(0, _list.Count - cntToRemain);
 
-                     notifyAction = NotifyCollectionChangedAction.Reset;
 
-                 }
 
-             }
 
-             // raise the collection changed event.
 
-             SynchronizationContext.SetSynchronizationContext(
 
-                 new DispatcherSynchronizationContext(Application.Current.Dispatcher));
 
-             SynchronizationContext.Current.Post(p1 =>
 
-             {
 
-                 CollectionChanged?.Invoke(
 
-                     this,
 
-                     new NotifyCollectionChangedEventArgs(notifyAction,
 
-                         notifyAction == NotifyCollectionChangedAction.Add ? itemsChanged : null));
 
-             }, null);
 
-             SynchronizationContext.Current.Post(p1 =>
 
-             {
 
-                 OnPropertyChanged(nameof(Count));
 
-             }, null);
 
-         }
 
-         public void Add(T newItem)
 
-         {
 
-             lock (_lockCache)
 
-             {
 
-                 _cache.Add(newItem);
 
-             }
 
-         }
 
-         public void Clear()
 
-         {
 
-             lock (_lockCache)
 
-             {
 
-                 _cache.Clear();
 
-             }
 
-             lock (_lockList)
 
-             {
 
-                 _list.Clear();
 
-             }
 
-         }
 
-         public IEnumerator<T> GetEnumerator()
 
-         {
 
-             lock (_lockList)
 
-             {
 
-                 _semListEnumLocker.Wait();
 
-                 return new SafeEnumerator<T>(_list.GetEnumerator(), _semListEnumLocker);
 
-             }
 
-         }
 
-         IEnumerator IEnumerable.GetEnumerator()
 
-         {
 
-             lock (_lockList)
 
-             {
 
-                 _semListEnumLocker.Wait();
 
-                 return new SafeEnumerator<T>(_list.GetEnumerator(), _semListEnumLocker);
 
-             }
 
-         }
 
-         public T this[int index]
 
-         {
 
-             get
 
-             {
 
-                 if (index < 0 || index >= Count)
 
-                     throw new ArgumentOutOfRangeException();
 
-                 lock (_lockList)
 
-                 {
 
-                     return _list[index];
 
-                 }
 
-             }
 
-         }
 
-         #endregion
 
-         public event PropertyChangedEventHandler PropertyChanged;
 
-         protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
 
-         {
 
-             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
-         }
 
-     }
 
- }
 
 
  |