Skip to content

Commit 260c034

Browse files
Ensure binding list provides RefreshItem when a refresh change is received (#678)
Binding List Refresh
1 parent 957135a commit 260c034

10 files changed

Lines changed: 306 additions & 50 deletions

.editorconfig

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ root = true
1010
insert_final_newline = true
1111
indent_style = space
1212
indent_size = 4
13+
dotnet_style_operator_placement_when_wrapping = beginning_of_line
14+
tab_width = 4
15+
end_of_line = crlf
16+
dotnet_style_coalesce_expression = true:suggestion
17+
dotnet_style_null_propagation = true:suggestion
18+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
19+
dotnet_style_prefer_auto_properties = true:suggestion
20+
dotnet_style_object_initializer = true:suggestion
21+
dotnet_style_collection_initializer = true:suggestion
22+
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
23+
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
24+
dotnet_style_prefer_conditional_expression_over_return = true:silent
25+
dotnet_style_explicit_tuple_names = true:suggestion
26+
dotnet_style_prefer_inferred_tuple_names = true:suggestion
27+
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
28+
dotnet_style_prefer_compound_assignment = true:suggestion
29+
dotnet_style_prefer_simplified_interpolation = true:suggestion
30+
dotnet_style_namespace_match_folder = true:suggestion
1331

1432
[project.json]
1533
indent_size = 2
@@ -54,15 +72,15 @@ dotnet_style_predefined_type_for_member_access = true:suggestion
5472
# name all constant fields using PascalCase
5573
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
5674
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
57-
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
75+
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
5876
dotnet_naming_symbols.constant_fields.applicable_kinds = field
5977
dotnet_naming_symbols.constant_fields.required_modifiers = const
6078
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
6179

6280
# static fields should have s_ prefix
6381
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
6482
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
65-
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
83+
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
6684
dotnet_naming_symbols.static_fields.applicable_kinds = field
6785
dotnet_naming_symbols.static_fields.required_modifiers = static
6886
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
@@ -72,7 +90,7 @@ dotnet_naming_style.static_prefix_style.capitalization = camel_case
7290
# internal and private fields should be _camelCase
7391
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
7492
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
75-
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
93+
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
7694
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
7795
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
7896
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
@@ -470,7 +488,7 @@ dotnet_diagnostic.SA1200.severity = none
470488

471489
dotnet_diagnostic.SA1201.severity = none
472490

473-
dotnet_diagnostic.SA1202.severity = error
491+
dotnet_diagnostic.SA1202.severity = silent
474492

475493
dotnet_diagnostic.SA1203.severity = error
476494

@@ -676,6 +694,9 @@ dotnet_diagnostic.SX1309.severity = error
676694

677695
dotnet_diagnostic.SX1623.severity = none
678696
dotnet_diagnostic.SX1309S.severity=silent
697+
csharp_style_namespace_declarations = block_scoped:silent
698+
csharp_style_prefer_method_group_conversion = true:silent
699+
csharp_style_prefer_top_level_statements = true:silent
679700

680701
# C++ Files
681702
[*.{cpp,h,in}]

src/Directory.build.targets

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
<Project>
2-
<PropertyGroup>
3-
<Product>$(AssemblyName) ($(TargetFramework))</Product>
4-
</PropertyGroup>
2+
<PropertyGroup>
3+
<Product>$(AssemblyName) ($(TargetFramework))</Product>
4+
</PropertyGroup>
55

6-
<PropertyGroup Condition="$(TargetFramework.StartsWith('uap'))">
7-
<DefineConstants>$(DefineConstants);WINDOWS_UWP;P_LINQ</DefineConstants>
8-
</PropertyGroup>
6+
<PropertyGroup Condition="$(TargetFramework.StartsWith('uap'))">
7+
<DefineConstants>$(DefineConstants);WINDOWS_UWP;P_LINQ</DefineConstants>
8+
</PropertyGroup>
99

10-
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
11-
<DefineConstants>$(DefineConstants);P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
12-
</PropertyGroup>
10+
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
11+
<DefineConstants>$(DefineConstants);P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
12+
</PropertyGroup>
1313

14-
<PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
15-
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
16-
</PropertyGroup>
14+
<PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
15+
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
16+
</PropertyGroup>
1717

18-
<PropertyGroup Condition="$(TargetFramework.StartsWith('netcoreapp'))">
19-
<DefineConstants>$(DefineConstants);NETCOREAPP;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
20-
</PropertyGroup>
18+
<PropertyGroup Condition="$(TargetFramework.StartsWith('netcoreapp'))">
19+
<DefineConstants>$(DefineConstants);NETCOREAPP;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
20+
</PropertyGroup>
2121

22-
<PropertyGroup Condition="$(TargetFramework.StartsWith('net5'))">
23-
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
24-
</PropertyGroup>
22+
<PropertyGroup Condition="$(TargetFramework.StartsWith('net5'))">
23+
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
24+
</PropertyGroup>
2525

26-
<PropertyGroup Condition="$(TargetFramework.StartsWith('net6'))">
27-
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
28-
</PropertyGroup>
26+
<PropertyGroup Condition="$(TargetFramework.StartsWith('net6'))">
27+
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
28+
</PropertyGroup>
2929

30+
<PropertyGroup Condition="$(TargetFramework.StartsWith('net7'))">
31+
<DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE;P_LINQ;SUPPORTS_BINDINGLIST</DefineConstants>
32+
</PropertyGroup>
3033
</Project>

src/DynamicData.Tests/Binding/BindingLIstBindListFixture.cs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ public BindingLIstBindListFixture()
2626
{
2727
_collection = new BindingList<Person>();
2828
_source = new SourceList<Person>();
29-
_binder = _source.Connect().Bind(_collection).Subscribe();
29+
_binder = _source.Connect()
30+
.AutoRefresh(p => p.Age)
31+
.Bind(_collection)
32+
.Subscribe();
3033
}
3134

3235
[Fact]
@@ -58,12 +61,29 @@ public void Clear()
5861
_collection.Count.Should().Be(0, "Should be 100 items in the collection");
5962
}
6063

61-
public void Dispose()
64+
65+
66+
[Fact]
67+
public void Refresh()
6268
{
63-
_binder.Dispose();
64-
_source.Dispose();
69+
var people = _generator.Take(100).ToList();
70+
_source.AddRange(people);
71+
72+
ListChangedEventArgs? args = null;
73+
74+
_collection.ListChanged += (_, e) =>
75+
{
76+
args = e;
77+
};
78+
79+
people[10].Age = 100;
80+
81+
args.Should().NotBeNull();
82+
args.ListChangedType.Should().Be(ListChangedType.ItemChanged);
83+
args.NewIndex.Should().Be(10);
6584
}
6685

86+
6787
[Fact]
6888
public void RemoveSourceRemovesFromTheDestination()
6989
{
@@ -85,6 +105,13 @@ public void UpdateToSourceUpdatesTheDestination()
85105
_collection.Count.Should().Be(1, "Should be 1 item in the collection");
86106
_collection.First().Should().Be(personUpdated, "Should be updated person");
87107
}
108+
109+
public void Dispose()
110+
{
111+
_binder.Dispose();
112+
_source.Dispose();
113+
}
114+
88115
}
89116
}
90-
#endif
117+
#endif

src/DynamicData.Tests/Binding/BindingListBindCacheFixture.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,6 @@ public void BatchRemove()
5757
_collection.Count.Should().Be(0, "Should be 100 items in the collection");
5858
}
5959

60-
public void Dispose()
61-
{
62-
_binder.Dispose();
63-
_source.Dispose();
64-
}
6560

6661
[Fact]
6762
public void RemoveSourceRemovesFromTheDestination()
@@ -73,6 +68,26 @@ public void RemoveSourceRemovesFromTheDestination()
7368
_collection.Count.Should().Be(0, "Should be 1 item in the collection");
7469
}
7570

71+
[Fact]
72+
public void Refresh()
73+
{
74+
var people = _generator.Take(100).ToList();
75+
_source.AddOrUpdate(people);
76+
77+
ListChangedEventArgs? args = null;
78+
79+
_collection.ListChanged += (_, e) =>
80+
{
81+
args = e;
82+
};
83+
84+
_source.Refresh(people[10]);
85+
86+
args.Should().NotBeNull();
87+
args.ListChangedType.Should().Be(ListChangedType.ItemChanged);
88+
args.NewIndex.Should().Be(10);
89+
}
90+
7691
[Fact]
7792
public void UpdateToSourceUpdatesTheDestination()
7893
{
@@ -84,6 +99,12 @@ public void UpdateToSourceUpdatesTheDestination()
8499
_collection.Count.Should().Be(1, "Should be 1 item in the collection");
85100
_collection.First().Should().Be(personUpdated, "Should be updated person");
86101
}
102+
103+
public void Dispose()
104+
{
105+
_binder.Dispose();
106+
_source.Dispose();
107+
}
87108
}
88109
}
89-
#endif
110+
#endif

src/DynamicData.Tests/Binding/BindingListBindCacheSortedFixture.cs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,6 @@ public void CollectionIsInSortOrder()
7070
sorted.Should().BeEquivalentTo(_collection.ToList());
7171
}
7272

73-
public void Dispose()
74-
{
75-
_binder.Dispose();
76-
_source.Dispose();
77-
}
7873

7974
[Fact]
8075
public void LargeUpdateInvokesAReset()
@@ -93,6 +88,28 @@ public void LargeUpdateInvokesAReset()
9388
invoked.Should().BeTrue();
9489
}
9590

91+
[Fact]
92+
public void Refresh()
93+
{
94+
var people = _generator.Take(100).ToList();
95+
_source.AddOrUpdate(people);
96+
97+
ListChangedEventArgs? args = null;
98+
99+
_collection.ListChanged += (_, e) =>
100+
{
101+
args = e;
102+
};
103+
104+
_source.Refresh(people[10]);
105+
106+
args.Should().NotBeNull();
107+
args.ListChangedType.Should().Be(ListChangedType.ItemChanged);
108+
109+
_collection[args.NewIndex].Should().Be(people[10]);
110+
}
111+
112+
96113
[Fact]
97114
public void RemoveSourceRemovesFromTheDestination()
98115
{
@@ -179,6 +196,15 @@ public void UpdateToSourceUpdatesTheDestination()
179196
_collection.Count.Should().Be(1, "Should be 1 item in the collection");
180197
_collection.First().Should().Be(personUpdated, "Should be updated person");
181198
}
199+
200+
201+
public void Dispose()
202+
{
203+
_binder.Dispose();
204+
_source.Dispose();
205+
}
182206
}
207+
208+
183209
}
184-
#endif
210+
#endif

src/DynamicData.Tests/Binding/BindingListToChangeSetFixture.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,12 @@ public void RefreshCausesReplace()
8080
sourceCacheResults.Messages.First().Adds.Should().Be(1);
8181
sourceCacheResults.Messages.Last().Refreshes.Should().Be(1);
8282

83-
// List receives add and replace instead of refresh
84-
collectionResults.Messages.Count.Should().Be(2);
83+
84+
/*
85+
List receives add and replace instead of refresh (and as of 23/02/2023 it receives a refresh too!)
86+
*/
87+
88+
collectionResults.Messages.Count.Should().Be(3);
8589
collectionResults.Messages.First().Adds.Should().Be(1);
8690
collectionResults.Messages.First().Refreshes.Should().Be(0);
8791
collectionResults.Messages.Last().Replaced.Should().Be(1);

src/DynamicData/Binding/BindingListAdaptor.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for full license information.
44

55
#if SUPPORTS_BINDINGLIST
6-
using System;
76
using System.ComponentModel;
87
using System.Diagnostics.CodeAnalysis;
98

@@ -129,10 +128,18 @@ private static void DoUpdate(IChangeSet<TObject, TKey> changes, BindingList<TObj
129128

130129
list.Add(update.Current);
131130
break;
131+
132+
case ChangeReason.Refresh:
133+
{
134+
var index = list.IndexOf(update.Current);
135+
if (index != -1)
136+
list.ResetItem(index);
137+
break;
138+
}
132139
}
133140
}
134141
}
135142
}
136143
}
137144

138-
#endif
145+
#endif

0 commit comments

Comments
 (0)