我们可能限制用户输入值范围,超出视为无效且引发错误,这就是设置最大值和最小值。NumberBox.razor在这里未作改动。
NumberBox.razor.cs 代码:
public partial class NumberBox<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TValue> : InputBase<TValue>
{
[Parameter]
public required string Lable { get; set; }
[Parameter]
public string InputWidth { get; set; } = "300";
[Parameter]
public bool Disabled { get; set; }
[Parameter]
public int? Max { get; set; }
[Parameter]
public int? Min { get; set; }
protected override void OnParametersSet()
{
base.OnParametersSet();
Lable += ":";
InputWidth += "px;";
Dictionary<string, object> keyValues = new();
if (Max.HasValue)
{
keyValues.Add("max", Max);
}
if (Min.HasValue)
{
keyValues.Add("min", Min);
}
AdditionalAttributes = keyValues;
}
//以下是复制于InputNumber 的源码,除了渲染部分注释掉外未作改动。
private static readonly string _stepAttributeValue = GetStepAttributeValue();
private static string GetStepAttributeValue()
{
// Unwrap Nullable<T>, because InputBase already deals with the Nullable aspect
// of it for us. We will only get asked to parse the T for nonempty inputs.
var targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue);
if (targetType == typeof(int) ||
targetType == typeof(long) ||
targetType == typeof(short) ||
targetType == typeof(float) ||
targetType == typeof(double) ||
targetType == typeof(decimal))
{
return "any";
}
else
{
throw new InvalidOperationException($"The type '{targetType}' is not a supported numeric type.");
}
}
/// <summary>
/// Gets or sets the error message used when displaying an a parsing error.
/// </summary>
[Parameter] public string ParsingErrorMessage { get; set; } = "The {0} field must be a number.";
/// <summary>
/// Gets or sets the associated <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; }
//这里是生成渲染树,我们用NumberBox.razor代替了。
/// <inheritdoc />
//protected override void BuildRenderTree(RenderTreeBuilder builder)
//{
// builder.OpenElement(0, "input");
// builder.AddAttribute(1, "step", _stepAttributeValue);
// builder.AddMultipleAttributes(2, AdditionalAttributes);
// builder.AddAttribute(3, "type", "number");
// builder.AddAttributeIfNotNullOrEmpty(4, "name", NameAttributeValue);
// builder.AddAttributeIfNotNullOrEmpty(5, "class", CssClass);
// builder.AddAttribute(6, "value", CurrentValueAsString);
// builder.AddAttribute(7, "onchange", EventCallback.Factory.CreateBinder<string?>(this, __value => CurrentValueAsString = __value, CurrentValueAsString));
// builder.SetUpdatesAttributeName("value");
// builder.AddElementReferenceCapture(8, __inputReference => Element = __inputReference);
// builder.CloseElement();
//}
/// <inheritdoc />
protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out TValue result, [NotNullWhen(false)] out string? validationErrorMessage)
{
if (BindConverter.TryConvertTo<TValue>(value, CultureInfo.InvariantCulture, out result))
{
if (Max.HasValue && value != null)
{
if (int.Parse(value) > Max)
{
validationErrorMessage = "数字最大为" + Max + "!";
return false;
}
}
if (Min.HasValue && value != null)
{
if (int.Parse(value) < Min)
{
validationErrorMessage = "数字最小为" + Min + "!";
return false;
}
}
validationErrorMessage = null;
return true;
}
else
{
validationErrorMessage = string.Format(CultureInfo.InvariantCulture, ParsingErrorMessage, DisplayName ?? FieldIdentifier.FieldName);
return false;
}
}
/// <summary>
/// Formats the value as a string. Derived classes can override this to determine the formatting used for <c>CurrentValueAsString</c>.
/// </summary>
/// <param name="value">The value to format.</param>
/// <returns>A string representation of the value.</returns>
protected override string? FormatValueAsString(TValue? value)
{
// Avoiding a cast to IFormattable to avoid boxing.
switch (value)
{
case null:
return null;
case int @int:
return BindConverter.FormatValue(@int, CultureInfo.InvariantCulture);
case long @long:
return BindConverter.FormatValue(@long, CultureInfo.InvariantCulture);
case short @short:
return BindConverter.FormatValue(@short, CultureInfo.InvariantCulture);
case float @float:
return BindConverter.FormatValue(@float, CultureInfo.InvariantCulture);
case double @double:
return BindConverter.FormatValue(@double, CultureInfo.InvariantCulture);
case decimal @decimal:
return BindConverter.FormatValue(@decimal, CultureInfo.InvariantCulture);
default:
throw new InvalidOperationException($"Unsupported type {value.GetType()}");
}
}
}
数值类型有好几种,但设置最大和最小一般为int类型,如果有特殊需求,代码就要复杂一点。