Skip to content
This repository was archived by the owner on Feb 25, 2021. It is now read-only.

Commit 702fcdb

Browse files
Extend ParameterEnumerator to list tree parameters too
1 parent 1644a3c commit 702fcdb

File tree

7 files changed

+164
-13
lines changed

7 files changed

+164
-13
lines changed

src/Microsoft.AspNetCore.Blazor/Components/ParameterCollection.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -19,15 +19,22 @@ public readonly struct ParameterCollection
1919
};
2020

2121
private static readonly ParameterCollection _emptyCollection
22-
= new ParameterCollection(_emptyCollectionFrames, 0);
22+
= new ParameterCollection(_emptyCollectionFrames, 0, null);
2323

2424
private readonly RenderTreeFrame[] _frames;
2525
private readonly int _ownerIndex;
26+
private readonly IReadOnlyList<TreeParameterState> _treeParametersOrNull;
2627

2728
internal ParameterCollection(RenderTreeFrame[] frames, int ownerIndex)
29+
: this(frames, ownerIndex, null)
30+
{
31+
}
32+
33+
private ParameterCollection(RenderTreeFrame[] frames, int ownerIndex, IReadOnlyList<TreeParameterState> treeParametersOrNull)
2834
{
2935
_frames = frames;
3036
_ownerIndex = ownerIndex;
37+
_treeParametersOrNull = treeParametersOrNull;
3138
}
3239

3340
/// <summary>
@@ -40,7 +47,7 @@ internal ParameterCollection(RenderTreeFrame[] frames, int ownerIndex)
4047
/// </summary>
4148
/// <returns>The enumerator.</returns>
4249
public ParameterEnumerator GetEnumerator()
43-
=> new ParameterEnumerator(_frames, _ownerIndex);
50+
=> new ParameterEnumerator(_frames, _ownerIndex, _treeParametersOrNull);
4451

4552
/// <summary>
4653
/// Gets the value of the parameter with the specified name.
@@ -99,6 +106,9 @@ public IReadOnlyDictionary<string, object> ToDictionary()
99106
return result;
100107
}
101108

109+
internal ParameterCollection WithTreeParameters(IReadOnlyList<TreeParameterState> treeParameters)
110+
=> new ParameterCollection(_frames, _ownerIndex, treeParameters);
111+
102112
// It's internal because there isn't a known use case for user code comparing
103113
// ParameterCollection instances, and even if there was, it's unlikely it should
104114
// use these equality rules which are designed for their effect on rendering.

src/Microsoft.AspNetCore.Blazor/Components/ParameterCollectionExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using Microsoft.AspNetCore.Blazor.Reflection;
5-
using Microsoft.AspNetCore.Blazor.RenderTree;
65
using System;
76
using System.Collections.Concurrent;
87
using System.Collections.Generic;

src/Microsoft.AspNetCore.Blazor/Components/ParameterEnumerator.cs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using Microsoft.AspNetCore.Blazor.RenderTree;
55
using System;
6+
using System.Collections.Generic;
67

78
namespace Microsoft.AspNetCore.Blazor.Components
89
{
@@ -11,25 +12,44 @@ namespace Microsoft.AspNetCore.Blazor.Components
1112
/// </summary>
1213
public struct ParameterEnumerator
1314
{
14-
RenderTreeFrameParameterEnumerator _renderTreeParamsEnumerator;
15+
private RenderTreeFrameParameterEnumerator _renderTreeParamsEnumerator;
16+
private TreeParameterEnumerator _treeParameterEnumerator;
17+
private bool _isEnumeratingRenderTreeParams;
1518

16-
internal ParameterEnumerator(RenderTreeFrame[] frames, int ownerIndex)
19+
internal ParameterEnumerator(RenderTreeFrame[] frames, int ownerIndex, IReadOnlyList<TreeParameterState> treeParameters)
1720
{
1821
_renderTreeParamsEnumerator = new RenderTreeFrameParameterEnumerator(frames, ownerIndex);
22+
_treeParameterEnumerator = new TreeParameterEnumerator(treeParameters);
23+
_isEnumeratingRenderTreeParams = true;
1924
}
2025

2126
/// <summary>
2227
/// Gets the current value of the enumerator.
2328
/// </summary>
24-
public Parameter Current
25-
=> _renderTreeParamsEnumerator.Current;
29+
public Parameter Current => _isEnumeratingRenderTreeParams
30+
? _renderTreeParamsEnumerator.Current
31+
: _treeParameterEnumerator.Current;
2632

2733
/// <summary>
2834
/// Instructs the enumerator to move to the next value in the sequence.
2935
/// </summary>
30-
/// <returns></returns>
36+
/// <returns>A flag to indicate whether or not there is a next value.</returns>
3137
public bool MoveNext()
32-
=> _renderTreeParamsEnumerator.MoveNext();
38+
{
39+
if (_isEnumeratingRenderTreeParams)
40+
{
41+
if (_renderTreeParamsEnumerator.MoveNext())
42+
{
43+
return true;
44+
}
45+
else
46+
{
47+
_isEnumeratingRenderTreeParams = false;
48+
}
49+
}
50+
51+
return _treeParameterEnumerator.MoveNext();
52+
}
3353

3454
struct RenderTreeFrameParameterEnumerator
3555
{
@@ -83,5 +103,41 @@ public bool MoveNext()
83103
return true;
84104
}
85105
}
106+
107+
struct TreeParameterEnumerator
108+
{
109+
private readonly IReadOnlyList<TreeParameterState> _treeParameters;
110+
private int _currentIndex;
111+
112+
public TreeParameterEnumerator(IReadOnlyList<TreeParameterState> treeParameters)
113+
{
114+
_treeParameters = treeParameters;
115+
_currentIndex = -1;
116+
}
117+
118+
public Parameter Current => new Parameter(
119+
_treeParameters[_currentIndex].LocalName,
120+
_treeParameters[_currentIndex].FromProvider.CurrentValue);
121+
122+
public bool MoveNext()
123+
{
124+
// Bail out early if there are no tree parameters
125+
if (_treeParameters == null)
126+
{
127+
return false;
128+
}
129+
130+
var nextIndex = _currentIndex + 1;
131+
if (nextIndex < _treeParameters.Count)
132+
{
133+
_currentIndex = nextIndex;
134+
return true;
135+
}
136+
else
137+
{
138+
return false;
139+
}
140+
}
141+
}
86142
}
87143
}

src/Microsoft.AspNetCore.Blazor/Components/Provider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public class Provider<T> : ProviderBase, IComponent
2323
/// </summary>
2424
[Parameter] private T Value { get; set; }
2525

26+
internal override object CurrentValue => Value;
27+
2628
/// <summary>
2729
/// Optionally gives a name to the provided value. Descendant components
2830
/// will be able to receive the value by specifying this name.

src/Microsoft.AspNetCore.Blazor/Components/ProviderBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ public abstract class ProviderBase
1414
// to work with all Provider types regardless of their generic param.
1515

1616
internal abstract bool CanSupplyValue(Type valueType, string providerName);
17+
18+
internal abstract object CurrentValue { get; }
1719
}
1820
}

src/Microsoft.AspNetCore.Blazor/Components/TreeParameterState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public TreeParameterState(string localName, ProviderBase fromProvider)
2323
FromProvider = fromProvider;
2424
}
2525

26-
public static ICollection<TreeParameterState> FindTreeParameters(ComponentState componentState)
26+
public static IReadOnlyList<TreeParameterState> FindTreeParameters(ComponentState componentState)
2727
{
2828
var componentType = componentState.Component.GetType();
2929
var infos = GetReflectedTreeParameterInfos(componentType);

test/Microsoft.AspNetCore.Blazor.Test/ParameterCollectionTest.cs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using Microsoft.AspNetCore.Blazor.Components;
@@ -85,6 +85,30 @@ public void EnumerationStopsAtEndOfOwnerAttributes()
8585
AssertParameter("attribute 2", attribute2Value));
8686
}
8787

88+
[Fact]
89+
public void EnumerationIncludesTreeParameters()
90+
{
91+
// Arrange
92+
var attribute1Value = new object();
93+
var attribute2Value = new object();
94+
var attribute3Value = new object();
95+
var parameterCollection = new ParameterCollection(new[]
96+
{
97+
RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2),
98+
RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value)
99+
}, 0).WithTreeParameters(new List<TreeParameterState>
100+
{
101+
new TreeParameterState("attribute 2", new TestProvider(attribute2Value)),
102+
new TreeParameterState("attribute 3", new TestProvider(attribute3Value)),
103+
});
104+
105+
// Assert
106+
Assert.Collection(ToEnumerable(parameterCollection),
107+
AssertParameter("attribute 1", attribute1Value),
108+
AssertParameter("attribute 2", attribute2Value),
109+
AssertParameter("attribute 3", attribute3Value));
110+
}
111+
88112
[Fact]
89113
public void CanTryGetNonExistingValue()
90114
{
@@ -140,6 +164,25 @@ public void CanGetValueOrDefault_WithExistingValue()
140164
Assert.Same(myEntryValue, result);
141165
}
142166

167+
[Fact]
168+
public void CanGetValueOrDefault_WithMultipleMatchingValues()
169+
{
170+
// Arrange
171+
var myEntryValue = new object();
172+
var parameterCollection = new ParameterCollection(new[]
173+
{
174+
RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3),
175+
RenderTreeFrame.Attribute(1, "my entry", myEntryValue),
176+
RenderTreeFrame.Attribute(1, "my entry", new object()),
177+
}, 0);
178+
179+
// Act
180+
var result = parameterCollection.GetValueOrDefault<object>("my entry");
181+
182+
// Assert: Picks first match
183+
Assert.Same(myEntryValue, result);
184+
}
185+
143186
[Fact]
144187
public void CanGetValueOrDefault_WithNonExistingValue()
145188
{
@@ -148,7 +191,10 @@ public void CanGetValueOrDefault_WithNonExistingValue()
148191
{
149192
RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2),
150193
RenderTreeFrame.Attribute(1, "some other entry", new object())
151-
}, 0);
194+
}, 0).WithTreeParameters(new List<TreeParameterState>
195+
{
196+
new TreeParameterState("another entry", new TestProvider(null))
197+
});
152198

153199
// Act
154200
var result = parameterCollection.GetValueOrDefault<DateTime>("nonexisting entry");
@@ -221,6 +267,29 @@ public void CanConvertToReadOnlyDictionary()
221267
});
222268
}
223269

270+
[Fact]
271+
public void CanGetValueOrDefault_WithMatchingTreeParameter()
272+
{
273+
// Arrange
274+
var myEntryValue = new object();
275+
var parameterCollection = new ParameterCollection(new[]
276+
{
277+
RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2),
278+
RenderTreeFrame.Attribute(1, "unrelated value", new object())
279+
}, 0).WithTreeParameters(new List<TreeParameterState>
280+
{
281+
new TreeParameterState("unrelated value 2", new TestProvider(null)),
282+
new TreeParameterState("my entry", new TestProvider(myEntryValue)),
283+
new TreeParameterState("unrelated value 3", new TestProvider(null)),
284+
});
285+
286+
// Act
287+
var result = parameterCollection.GetValueOrDefault<object>("my entry");
288+
289+
// Assert
290+
Assert.Same(myEntryValue, result);
291+
}
292+
224293
private Action<Parameter> AssertParameter(string expectedName, object expectedValue)
225294
{
226295
return parameter =>
@@ -246,5 +315,18 @@ public void Init(RenderHandle renderHandle)
246315
public void SetParameters(ParameterCollection parameters)
247316
=> throw new NotImplementedException();
248317
}
318+
319+
private class TestProvider : ProviderBase
320+
{
321+
public TestProvider(object value)
322+
{
323+
CurrentValue = value;
324+
}
325+
326+
internal override object CurrentValue { get; }
327+
328+
internal override bool CanSupplyValue(Type valueType, string providerName)
329+
=> throw new NotImplementedException();
330+
}
249331
}
250332
}

0 commit comments

Comments
 (0)