Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/DynamicData/Binding/BindPaged.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Roland Pheasant licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Reactive.Concurrency;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
Expand All @@ -14,7 +14,7 @@ namespace DynamicData.Binding;
*
* (Direct lift from BindVirtualized).
*/
internal sealed class BindPaged<TObject, TKey>(
internal sealed class BindPaged<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>(
IObservable<IChangeSet<TObject, TKey, PageContext<TObject>>> source,
IList<TObject> targetList,
SortAndBindOptions? options)
Expand Down
4 changes: 2 additions & 2 deletions src/DynamicData/Binding/BindVirtualized.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Roland Pheasant licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Reactive.Concurrency;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
Expand All @@ -12,7 +12,7 @@ namespace DynamicData.Binding;
/*
* Binding for the result of the SortAndVirtualize operator
*/
internal sealed class BindVirtualized<TObject, TKey>(
internal sealed class BindVirtualized<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>(
IObservable<IChangeSet<TObject, TKey, VirtualContext<TObject>>> source,
IList<TObject> targetList,
SortAndBindOptions? options)
Expand Down
187 changes: 93 additions & 94 deletions src/DynamicData/Binding/BindingListAdaptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,120 +8,119 @@
using DynamicData.Cache;
using DynamicData.Cache.Internal;

namespace DynamicData.Binding
namespace DynamicData.Binding;

/// <summary>
/// Adaptor to reflect a change set into a binding list.
/// </summary>
/// <typeparam name="T">The type of items.</typeparam>
/// <remarks>
/// Initializes a new instance of the <see cref="BindingListAdaptor{T}"/> class.
/// </remarks>
/// <param name="list">The list of items to add to the adapter.</param>
/// <param name="refreshThreshold">The threshold before a reset is issued.</param>
public class BindingListAdaptor<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(BindingList<T> list, int refreshThreshold = BindingOptions.DefaultResetThreshold) : IChangeSetAdaptor<T>
where T : notnull
{
/// <summary>
/// Adaptor to reflect a change set into a binding list.
/// </summary>
/// <typeparam name="T">The type of items.</typeparam>
/// <remarks>
/// Initializes a new instance of the <see cref="BindingListAdaptor{T}"/> class.
/// </remarks>
/// <param name="list">The list of items to add to the adapter.</param>
/// <param name="refreshThreshold">The threshold before a reset is issued.</param>
public class BindingListAdaptor<T>(BindingList<T> list, int refreshThreshold = BindingOptions.DefaultResetThreshold) : IChangeSetAdaptor<T>
where T : notnull
private readonly BindingList<T> _list = list ?? throw new ArgumentNullException(nameof(list));
private bool _loaded;

/// <inheritdoc />
public void Adapt(IChangeSet<T> changes)
{
private readonly BindingList<T> _list = list ?? throw new ArgumentNullException(nameof(list));
private bool _loaded;
changes.ThrowArgumentNullExceptionIfNull(nameof(changes));

/// <inheritdoc />
public void Adapt(IChangeSet<T> changes)
if (changes.TotalChanges - changes.Refreshes > refreshThreshold || !_loaded)
{
changes.ThrowArgumentNullExceptionIfNull(nameof(changes));

if (changes.TotalChanges - changes.Refreshes > refreshThreshold || !_loaded)
{
using (new BindingListEventsSuspender<T>(_list))
{
_list.Clone(changes);
_loaded = true;
}
}
else
using (new BindingListEventsSuspender<T>(_list))
{
_list.Clone(changes);
_loaded = true;
}
}
else
{
_list.Clone(changes);
}
}
}

/// <summary>
/// Adaptor to reflect a change set into a binding list.
/// </summary>
/// <typeparam name="TObject">The type of the object.</typeparam>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <remarks>
/// Initializes a new instance of the <see cref="BindingListAdaptor{TObject, TKey}"/> class.
/// </remarks>
/// <param name="list">The list of items to adapt.</param>
/// <param name="refreshThreshold">The threshold before the refresh is triggered.</param>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Same class name, different generics")]
public class BindingListAdaptor<TObject, TKey>(BindingList<TObject> list, int refreshThreshold = BindingOptions.DefaultResetThreshold) : IChangeSetAdaptor<TObject, TKey>
where TObject : notnull
where TKey : notnull
{
private readonly Cache<TObject, TKey> _cache = new();
/// <summary>
/// Adaptor to reflect a change set into a binding list.
/// </summary>
/// <typeparam name="TObject">The type of the object.</typeparam>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <remarks>
/// Initializes a new instance of the <see cref="BindingListAdaptor{TObject, TKey}"/> class.
/// </remarks>
/// <param name="list">The list of items to adapt.</param>
/// <param name="refreshThreshold">The threshold before the refresh is triggered.</param>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Same class name, different generics")]
public class BindingListAdaptor<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>(BindingList<TObject> list, int refreshThreshold = BindingOptions.DefaultResetThreshold) : IChangeSetAdaptor<TObject, TKey>
where TObject : notnull
where TKey : notnull
{
private readonly Cache<TObject, TKey> _cache = new();

private readonly BindingList<TObject> _list = list ?? throw new ArgumentNullException(nameof(list));
private bool _loaded;
private readonly BindingList<TObject> _list = list ?? throw new ArgumentNullException(nameof(list));
private bool _loaded;

/// <inheritdoc />
public void Adapt(IChangeSet<TObject, TKey> changes)
{
changes.ThrowArgumentNullExceptionIfNull(nameof(changes));
_cache.Clone(changes);
/// <inheritdoc />
public void Adapt(IChangeSet<TObject, TKey> changes)
{
changes.ThrowArgumentNullExceptionIfNull(nameof(changes));
_cache.Clone(changes);

if (changes.Count - changes.Refreshes > refreshThreshold || !_loaded)
{
using (new BindingListEventsSuspender<TObject>(_list))
{
_list.Clear();
_list.AddRange(_cache.Items);
_loaded = true;
}
}
else
if (changes.Count - changes.Refreshes > refreshThreshold || !_loaded)
{
using (new BindingListEventsSuspender<TObject>(_list))
{
DoUpdate(changes, _list);
_list.Clear();
_list.AddRange(_cache.Items);
_loaded = true;
}
}
else
{
DoUpdate(changes, _list);
}
}

private static void DoUpdate(IChangeSet<TObject, TKey> changes, BindingList<TObject> list)
private static void DoUpdate(IChangeSet<TObject, TKey> changes, BindingList<TObject> list)
{
foreach (var update in changes.ToConcreteType())
{
foreach (var update in changes.ToConcreteType())
switch (update.Reason)
{
switch (update.Reason)
{
case ChangeReason.Add:
case ChangeReason.Add:
list.Add(update.Current);
break;

case ChangeReason.Remove:
list.Remove(update.Current);
break;

case ChangeReason.Update:
var previousIndex = list.IndexOf(update.Previous.Value);
if (previousIndex >= 0)
{
list[previousIndex] = update.Current;
}
else
{
list.Add(update.Current);
break;

case ChangeReason.Remove:
list.Remove(update.Current);
break;

case ChangeReason.Update:
var previousIndex = list.IndexOf(update.Previous.Value);
if (previousIndex >= 0)
{
list[previousIndex] = update.Current;
}
else
{
list.Add(update.Current);
}

break;

case ChangeReason.Refresh:
var index = list.IndexOf(update.Current);
if (index != -1)
{
list.ResetItem(index);
}

break;
}
}

break;

case ChangeReason.Refresh:
var index = list.IndexOf(update.Current);
if (index != -1)
{
list.ResetItem(index);
}

break;
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/DynamicData/Binding/BindingListEventsSuspender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
// See the LICENSE file in the project root for full license information.

using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables;

namespace DynamicData.Binding;

internal sealed class BindingListEventsSuspender<T> : IDisposable
internal sealed class BindingListEventsSuspender<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : IDisposable
{
private readonly IDisposable _cleanUp;

Expand Down
3 changes: 2 additions & 1 deletion src/DynamicData/Binding/SortAndBind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for full license information.

using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using DynamicData.Cache;
Expand All @@ -17,7 +18,7 @@ namespace DynamicData.Binding;
* collection upon every change in order that the sorted list could be transmitted to the bind operator.
*
*/
internal sealed class SortAndBind<TObject, TKey>
internal sealed class SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>
where TObject : notnull
where TKey : notnull
{
Expand Down
Loading