Files
2025-11-03 11:03:45 +01:00

90 lines
2.4 KiB
Plaintext

@using System.Globalization
<input value="@DisplayValue"
@onchange="OnChange"
class="@CssClass" />
@code {
/// <summary>
/// Actual bind value
/// </summary>
[Parameter]
public decimal Value { get; set; }
/// <summary>
/// Event for value changed
/// </summary>
[Parameter]
public EventCallback<decimal> ValueChanged { get; set; }
/// <summary>
/// CssClass for input component
/// </summary>
[Parameter]
public string CssClass { get; set; } = string.Empty;
/// <summary>
/// Number of decimal places to display in percentage format.
/// Example: Decimals=2 → "15.00%".
/// </summary>
[Parameter]
public int Decimals { get; set; } = 2;
/// <summary>
/// If true, parsing is always done with InvariantCulture.
/// If false (default), try CurrentCulture first, then InvariantCulture.
/// </summary>
[Parameter]
public bool ForceInvariantParsing { get; set; } = false;
/// <summary>
/// Percentage format string
/// </summary>
private string DisplayValue => Value.ToString($"P{Decimals}");
/// <summary>
/// Change value event
/// </summary>
private async Task OnChange(ChangeEventArgs e)
{
var input = e.Value?.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(input))
{
Value = 0;
await ValueChanged.InvokeAsync(0);
return;
}
// Remove % if present
var cleaned = input.Replace("%", "").Trim();
decimal parsed;
bool success;
if (ForceInvariantParsing)
{
// Option 3: Always invariant
success = decimal.TryParse(cleaned, NumberStyles.Any, CultureInfo.InvariantCulture, out parsed);
}
else
{
// Option 2: Try current culture, then invariant
success = decimal.TryParse(cleaned, NumberStyles.Any, CultureInfo.CurrentCulture, out parsed)
|| decimal.TryParse(cleaned, NumberStyles.Any, CultureInfo.InvariantCulture, out parsed);
}
if (success)
{
decimal result = parsed <= 1 ? parsed : parsed / 100;
Value = result;
await ValueChanged.InvokeAsync(result);
}
else
{
// Invalid input → reset to 0
Value = 0;
await ValueChanged.InvokeAsync(0);
}
}
}