-
Notifications
You must be signed in to change notification settings - Fork 9.9k
/
InputSelect.cs
90 lines (78 loc) · 3.53 KB
/
InputSelect.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Microsoft.AspNetCore.Components.Rendering;
namespace Microsoft.AspNetCore.Components.Forms
{
/// <summary>
/// A dropdown selection component.
/// </summary>
public class InputSelect<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TValue> : InputBase<TValue>
{
private readonly bool _isMultipleSelect;
/// <summary>
/// Constructs an instance of <see cref="InputSelect{TValue}"/>.
/// </summary>
public InputSelect()
{
_isMultipleSelect = typeof(TValue).IsArray;
}
/// <summary>
/// Gets or sets the child content to be rendering inside the select element.
/// </summary>
[Parameter] public RenderFragment? ChildContent { get; set; }
/// <summary>
/// Gets or sets the <c>select</c> <see cref="ElementReference"/>.
/// <para>
/// May be <see langword="null"/> if accessed before the component is rendered.
/// </para>
/// </summary>
[DisallowNull] public ElementReference? Element { get; protected set; }
/// <inheritdoc />
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "select");
builder.AddMultipleAttributes(1, AdditionalAttributes);
builder.AddAttribute(2, "class", CssClass);
builder.AddAttribute(3, "multiple", _isMultipleSelect);
if (_isMultipleSelect)
{
builder.AddAttribute(4, "value", BindConverter.FormatValue(CurrentValue)?.ToString());
builder.AddAttribute(5, "onchange", EventCallback.Factory.CreateBinder<string?[]?>(this, SetCurrentValueAsStringArray, default));
}
else
{
builder.AddAttribute(6, "value", CurrentValueAsString);
builder.AddAttribute(7, "onchange", EventCallback.Factory.CreateBinder<string?>(this, __value => CurrentValueAsString = __value, default));
}
builder.AddElementReferenceCapture(8, __selectReference => Element = __selectReference);
builder.AddContent(9, ChildContent);
builder.CloseElement();
}
/// <inheritdoc />
protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out TValue result, [NotNullWhen(false)] out string? validationErrorMessage)
=> this.TryParseSelectableValueFromString(value, out result, out validationErrorMessage);
/// <inheritdoc />
protected override string? FormatValueAsString(TValue? value)
{
// We special-case bool values because BindConverter reserves bool conversion for conditional attributes.
if (typeof(TValue) == typeof(bool))
{
return (bool)(object)value! ? "true" : "false";
}
else if (typeof(TValue) == typeof(bool?))
{
return value is not null && (bool)(object)value ? "true" : "false";
}
return base.FormatValueAsString(value);
}
private void SetCurrentValueAsStringArray(string?[]? value)
{
CurrentValue = BindConverter.TryConvertTo<TValue>(value, CultureInfo.CurrentCulture, out var result)
? result
: default;
}
}
}