Skip to content

Commit

Permalink
Binding options - allow system wide options (#776)
Browse files Browse the repository at this point in the history
* Binding options - allow system wide options + use constants for system defaults
  • Loading branch information
RolandPheasant authored Dec 3, 2023
1 parent 70e02b5 commit 3d4543f
Show file tree
Hide file tree
Showing 10 changed files with 641 additions and 90 deletions.
6 changes: 4 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_prefer_collection_expression = true:suggestion

[project.json]
indent_size = 2
Expand Down Expand Up @@ -492,7 +493,7 @@ dotnet_diagnostic.SA1202.severity = silent

dotnet_diagnostic.SA1203.severity = error

dotnet_diagnostic.SA1204.severity = error
dotnet_diagnostic.SA1204.severity = none

dotnet_diagnostic.SA1205.severity = error

Expand Down Expand Up @@ -548,7 +549,7 @@ dotnet_diagnostic.SA1400.severity = error

dotnet_diagnostic.SA1401.severity = error

dotnet_diagnostic.SA1402.severity = error
dotnet_diagnostic.SA1402.severity = none

dotnet_diagnostic.SA1403.severity = error

Expand Down Expand Up @@ -697,6 +698,7 @@ dotnet_diagnostic.SX1309S.severity=silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion

# C++ Files
[*.{cpp,h,in}]
Expand Down
96 changes: 95 additions & 1 deletion src/DynamicData.Tests/Binding/IObservableListBindListFixture.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;

using System.Reactive.Linq;
using DynamicData.Binding;
using DynamicData.Tests.Domain;

Expand Down Expand Up @@ -30,6 +32,98 @@ public IObservableListBindListFixture()
_observableListNotifications = _list.Connect().AsAggregator();
}

[Fact]
public void ResetThresholdsForBinding_ObservableCollection()
{
var people = _generator.Take(100).ToArray();

// check whether reset is fired with different params
var test1 = Test();
var test2 = Test(new BindingOptions(95));
var test3 = Test(new BindingOptions(105, ResetOnFirstTimeLoad: false));
var test4 = Test(BindingOptions.NeverFireReset());


test1.action.Should().Be(NotifyCollectionChangedAction.Reset);
test2.action.Should().Be(NotifyCollectionChangedAction.Reset);
test3.action.Should().Be(NotifyCollectionChangedAction.Add);
test4.action.Should().Be(NotifyCollectionChangedAction.Add);

return;

(NotifyCollectionChangedAction action, ObservableCollectionExtended<Person> list) Test(BindingOptions? options = null)
{
_source.Clear();

NotifyCollectionChangedAction? result = null;

var list = new ObservableCollectionExtended<Person>();
using var listEvents = list.ObserveCollectionChanges().Take(1)
.Select(e => e.EventArgs.Action)
.Subscribe(events =>
{
result = events;
});


var binder = options == null
? _source.Connect().Bind(list).Subscribe()
: _source.Connect().Bind(list, options.Value).Subscribe();

_source.AddRange(people);
binder.Dispose();

return (result!.Value, list);
}
}

[Fact]
public void ResetThresholdsForBinding_ReadonlyObservableCollection()
{
var people = _generator.Take(100).ToArray();


// check whether reset is fired with different params
var test1 = Test();
var test2 = Test(new BindingOptions(95));
var test3 = Test(new BindingOptions(105, ResetOnFirstTimeLoad: false));
var test4 = Test(BindingOptions.NeverFireReset());


test1.action.Should().Be(NotifyCollectionChangedAction.Reset);
test2.action.Should().Be(NotifyCollectionChangedAction.Reset);
test3.action.Should().Be(NotifyCollectionChangedAction.Add);
test4.action.Should().Be(NotifyCollectionChangedAction.Add);

return;

(NotifyCollectionChangedAction action, ReadOnlyObservableCollection<Person> list) Test(BindingOptions? options = null)
{
_source.Clear();

NotifyCollectionChangedAction? result = null;
ReadOnlyObservableCollection<Person> list;
//var list = new ObservableCollectionExtended<Person>();

var binder = options == null
? _source.Connect().Bind(out list).Subscribe()
: _source.Connect().Bind(out list, options.Value).Subscribe();

using var listEvents = list.ObserveCollectionChanges().Take(1)
.Select(e => e.EventArgs.Action)
.Subscribe(events =>
{
result = events;
});

_source.AddRange(people);
binder.Dispose();
return (result!.Value, list);
}
}



[Fact]
public void AddRange()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq;
Expand Down Expand Up @@ -28,6 +29,99 @@ public ObservableCollectionBindCacheFixture()
_binder = _source.Connect().Bind(_collection).Subscribe();
}

[Fact]
public void ResetThresholdsForBinding_ObservableCollection()
{
var people = _generator.Take(100).ToArray();



// check whether reset is fired with different params
var test1 = Test();
var test2 = Test(new BindingOptions(95));
var test3 = Test(new BindingOptions(105, ResetOnFirstTimeLoad: false));
var test4 = Test(BindingOptions.NeverFireReset());


test1.action.Should().Be(NotifyCollectionChangedAction.Reset);
test2.action.Should().Be(NotifyCollectionChangedAction.Reset);
test3.action.Should().Be(NotifyCollectionChangedAction.Add);
test4.action.Should().Be(NotifyCollectionChangedAction.Add);

return;

(NotifyCollectionChangedAction action, ObservableCollectionExtended<Person> list) Test(BindingOptions? options = null)
{
_source.Clear();

NotifyCollectionChangedAction? result = null;

var list = new ObservableCollectionExtended<Person>();
using var listEvents = list.ObserveCollectionChanges().Take(1)
.Select(e => e.EventArgs.Action)
.Subscribe(events =>
{
result = events;
});


var binder = options == null
? _source.Connect().Bind(list).Subscribe()
: _source.Connect().Bind(list, options.Value).Subscribe();

_source.AddOrUpdate(people);
binder.Dispose();

return (result!.Value, list);
}
}

[Fact]
public void ResetThresholdsForBinding_ReadonlyObservableCollection()
{
var people = _generator.Take(100).ToArray();


// check whether reset is fired with different params
var test1 = Test();
var test2 = Test(new BindingOptions(95));
var test3 = Test(new BindingOptions(105, ResetOnFirstTimeLoad: false));
var test4 = Test(BindingOptions.NeverFireReset());


test1.action.Should().Be(NotifyCollectionChangedAction.Reset);
test2.action.Should().Be(NotifyCollectionChangedAction.Reset);
test3.action.Should().Be(NotifyCollectionChangedAction.Add);
test4.action.Should().Be(NotifyCollectionChangedAction.Add);

return;

(NotifyCollectionChangedAction action, ReadOnlyObservableCollection<Person> list) Test(BindingOptions? options = null)
{
_source.Clear();

NotifyCollectionChangedAction? result = null;
ReadOnlyObservableCollection<Person> list;
//var list = new ObservableCollectionExtended<Person>();

var binder = options == null
? _source.Connect().Bind(out list).Subscribe()
: _source.Connect().Bind(out list, options.Value).Subscribe();

using var listEvents = list.ObserveCollectionChanges().Take(1)
.Select(e => e.EventArgs.Action)
.Subscribe(events =>
{
result = events;
});

_source.AddOrUpdate(people);
binder.Dispose();
return (result!.Value, list);
}
}


[Fact]
public void AddToSourceAddsToDestination()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq;
Expand All @@ -8,7 +9,6 @@
using DynamicData.Tests.Domain;

using FluentAssertions;

using Xunit;

namespace DynamicData.Tests.Binding;
Expand All @@ -17,11 +17,11 @@ public class ObservableCollectionBindCacheSortedFixture : IDisposable
{
private readonly IDisposable _binder;

private readonly ObservableCollectionExtended<Person> _collection = new ObservableCollectionExtended<Person>();
private readonly ObservableCollectionExtended<Person> _collection;

private readonly IComparer<Person> _comparer = SortExpressionComparer<Person>.Ascending(p => p.Name);

private readonly RandomPersonGenerator _generator = new RandomPersonGenerator();
private readonly RandomPersonGenerator _generator = new();

private readonly ISourceCache<Person, string> _source;

Expand All @@ -32,6 +32,99 @@ public ObservableCollectionBindCacheSortedFixture()
_binder = _source.Connect().Sort(_comparer, resetThreshold: 25).Bind(_collection).Subscribe();
}


[Fact]
public void ResetThresholdsForBinding_ObservableCollection()
{
var people = _generator.Take(100).ToArray();



// check whether reset is fired with different params
var test1 = Test();
var test2 = Test(new BindingOptions(95));
var test3 = Test(new BindingOptions(105, ResetOnFirstTimeLoad: false));
var test4 = Test(BindingOptions.NeverFireReset());


test1.action.Should().Be(NotifyCollectionChangedAction.Reset);
test2.action.Should().Be(NotifyCollectionChangedAction.Reset);
test3.action.Should().Be(NotifyCollectionChangedAction.Add);
test4.action.Should().Be(NotifyCollectionChangedAction.Add);

return;

(NotifyCollectionChangedAction action, ObservableCollectionExtended<Person> list) Test(BindingOptions? options = null)
{
_source.Clear();

NotifyCollectionChangedAction? result = null;

var list = new ObservableCollectionExtended<Person>();
using var listEvents = list.ObserveCollectionChanges().Take(1)
.Select(e => e.EventArgs.Action)
.Subscribe(events =>
{
result = events;
});


var binder = options == null
? _source.Connect().Sort(_comparer).Bind(list).Subscribe()
: _source.Connect().Sort(_comparer).Bind(list, options.Value).Subscribe();

_source.AddOrUpdate(people);
binder.Dispose();

return (result!.Value, list);
}
}

[Fact]
public void ResetThresholdsForBinding_ReadonlyObservableCollection()
{
var people = _generator.Take(100).ToArray();


// check whether reset is fired with different params
var test1 = Test();
var test2 = Test(new BindingOptions(95));
var test3 = Test(new BindingOptions(105, ResetOnFirstTimeLoad: false));
var test4 = Test(BindingOptions.NeverFireReset());


test1.action.Should().Be(NotifyCollectionChangedAction.Reset);
test2.action.Should().Be(NotifyCollectionChangedAction.Reset);
test3.action.Should().Be(NotifyCollectionChangedAction.Add);
test4.action.Should().Be(NotifyCollectionChangedAction.Add);

return;

(NotifyCollectionChangedAction action, ReadOnlyObservableCollection<Person> list) Test(BindingOptions? options = null)
{
_source.Clear();

NotifyCollectionChangedAction? result = null;
ReadOnlyObservableCollection<Person> list;
//var list = new ObservableCollectionExtended<Person>();

var binder = options == null
? _source.Connect().Sort(_comparer).Bind(out list).Subscribe()
: _source.Connect().Sort(_comparer).Bind(out list, options.Value).Subscribe();

using var listEvents = list.ObserveCollectionChanges().Take(1)
.Select(e => e.EventArgs.Action)
.Subscribe(events =>
{
result = events;
});

_source.AddOrUpdate(people);
binder.Dispose();
return (result!.Value, list);
}
}

[Fact]
public void AddToSourceAddsToDestination()
{
Expand Down
4 changes: 2 additions & 2 deletions src/DynamicData/Binding/BindingListAdaptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class BindingListAdaptor<T> : IChangeSetAdaptor<T>
/// </summary>
/// <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 BindingListAdaptor(BindingList<T> list, int refreshThreshold = 25)
public BindingListAdaptor(BindingList<T> list, int refreshThreshold = BindingOptions.DefaultResetThreshold)
{
_list = list ?? throw new ArgumentNullException(nameof(list));
_refreshThreshold = refreshThreshold;
Expand Down Expand Up @@ -80,7 +80,7 @@ public class BindingListAdaptor<TObject, TKey> : IChangeSetAdaptor<TObject, TKey
/// </summary>
/// <param name="list">The list of items to adapt.</param>
/// <param name="refreshThreshold">The threshold before the refresh is triggered.</param>
public BindingListAdaptor(BindingList<TObject> list, int refreshThreshold = 25)
public BindingListAdaptor(BindingList<TObject> list, int refreshThreshold = BindingOptions.DefaultResetThreshold)
{
_list = list ?? throw new ArgumentNullException(nameof(list));
_refreshThreshold = refreshThreshold;
Expand Down
Loading

0 comments on commit 3d4543f

Please sign in to comment.