Skip to content

Commit

Permalink
Replace ArrayList/ICollection used for changelog in CollectionView wi…
Browse files Browse the repository at this point in the history
…th generic List (#9853)

* Replace ArrayList/ICollection with List<NotifyCollectionChangedEventArgs>

* Rename EmptyArrayList -> s_emptyList

* Values inside changeLog can never be NULL and we no longer need to cast

* _changeLog can never be NULL, re-init is under same lock
  • Loading branch information
h3xds1nz authored Dec 31, 2024
1 parent c8c970b commit 43eb4e6
Showing 1 changed file with 25 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ protected virtual void OnAllowsCrossThreadChangesChanged()
/// </notes>
protected void ClearPendingChanges()
{
lock(_changeLog.SyncRoot)
lock (_changeLogLock)
{
_changeLog.Clear();
_tempChangeLog.Clear();
Expand All @@ -1227,7 +1227,7 @@ protected void ClearPendingChanges()
/// </notes>
protected void ProcessPendingChanges()
{
lock(_changeLog.SyncRoot)
lock (_changeLogLock)
{
ProcessChangeLog(_changeLog, true);
_changeLog.Clear();
Expand Down Expand Up @@ -1815,24 +1815,17 @@ private void EndDefer()
/// processed.
/// </summary>
/// <param name="changeLog">
/// ArrayList of NotifyCollectionChangedEventArgs that could not be precessed.
/// List of NotifyCollectionChangedEventArgs that could not be precessed.
/// </param>
private void DeferProcessing(ICollection changeLog)
private void DeferProcessing(List<NotifyCollectionChangedEventArgs> changeLog)
{
Debug.Assert(changeLog != null && changeLog.Count > 0, "don't defer when there's no work");

lock(SyncRoot)
lock (SyncRoot)
{
lock(_changeLog.SyncRoot)
lock (_changeLogLock)
{
if (_changeLog == null)
{
_changeLog = new ArrayList(changeLog);
}
else
{
_changeLog.InsertRange(0, changeLog);
}
_changeLog.InsertRange(0, changeLog);

if (_databindOperation != null)
{
Expand All @@ -1854,21 +1847,15 @@ private void DeferProcessing(ICollection changeLog)
/// <param name="changeLog">
/// List of NotifyCollectionChangedEventArgs that is to be processed.
/// </param>
private ICollection ProcessChangeLog(ArrayList changeLog, bool processAll=false)
private List<NotifyCollectionChangedEventArgs> ProcessChangeLog(List<NotifyCollectionChangedEventArgs> changeLog, bool processAll = false)
{
int currentIndex = 0;
bool mustDeferProcessing = false;
long beginTime = DateTime.Now.Ticks;
int startCount = changeLog.Count;

for ( ; currentIndex < changeLog.Count && !(mustDeferProcessing); currentIndex++)
for ( ; currentIndex < changeLog.Count && !mustDeferProcessing; currentIndex++)
{
NotifyCollectionChangedEventArgs args = changeLog[currentIndex] as NotifyCollectionChangedEventArgs;

if (args != null)
{
ProcessCollectionChanged(args);
}
ProcessCollectionChanged(changeLog[currentIndex]);

if (!processAll)
{
Expand All @@ -1879,7 +1866,7 @@ private ICollection ProcessChangeLog(ArrayList changeLog, bool processAll=false)
if (mustDeferProcessing && currentIndex < changeLog.Count)
{
// create an unprocessed subset of changeLog
changeLog.RemoveRange(0,currentIndex);
changeLog.RemoveRange(0, currentIndex);
return changeLog;
}

Expand Down Expand Up @@ -1907,9 +1894,9 @@ private void SetFlag(CollectionViewFlags flags, bool value)
// Post a change on the UI thread Dispatcher and updated the _changeLog.
private void PostChange(NotifyCollectionChangedEventArgs args)
{
lock(SyncRoot)
lock (SyncRoot)
{
lock(_changeLog.SyncRoot)
lock (_changeLogLock)
{
// we can ignore everything before a Reset
if (args.Action == NotifyCollectionChangedAction.Reset)
Expand Down Expand Up @@ -1948,26 +1935,26 @@ private object ProcessInvoke(object arg)
{
// work on a private copy of the change log, so that other threads
// can add to the main change log
lock(SyncRoot)
lock (SyncRoot)
{
lock(_changeLog.SyncRoot)
lock (_changeLogLock)
{
_databindOperation = null;
_tempChangeLog = _changeLog;
_changeLog = new ArrayList();
_changeLog = new List<NotifyCollectionChangedEventArgs>();
}
}

// process the changes
ICollection unprocessedChanges = ProcessChangeLog(_tempChangeLog);
List<NotifyCollectionChangedEventArgs> unprocessedChanges = ProcessChangeLog(_tempChangeLog);

// if changes remain (because we ran out of time), reschedule them
if (unprocessedChanges != null && unprocessedChanges.Count > 0)
{
DeferProcessing(unprocessedChanges);
}

_tempChangeLog = EmptyArrayList;
_tempChangeLog = s_emptyList;

return null;
}
Expand Down Expand Up @@ -2154,8 +2141,11 @@ private enum CollectionViewFlags
//------------------------------------------------------
#region Private Fields

ArrayList _changeLog = new ArrayList();
ArrayList _tempChangeLog = EmptyArrayList;
private readonly Lock _changeLogLock = new();

private List<NotifyCollectionChangedEventArgs> _changeLog = new();
private List<NotifyCollectionChangedEventArgs> _tempChangeLog = s_emptyList;

DataBindOperation _databindOperation;
object _vmData; // view manager's private data
IEnumerable _sourceCollection; // the underlying collection
Expand All @@ -2173,7 +2163,8 @@ private enum CollectionViewFlags
object _syncObject = new object();
DataBindEngine _engine;
int _timestamp;
static readonly ArrayList EmptyArrayList = new ArrayList();

private static readonly List<NotifyCollectionChangedEventArgs> s_emptyList = new();
static readonly string IEnumerableT = typeof(IEnumerable<>).Name;
internal static readonly object NoNewItem = new NamedObject("NoNewItem");

Expand Down

0 comments on commit 43eb4e6

Please # to comment.