@using System.Globalization
@code {
///
/// Actual bind value
///
[Parameter]
public decimal Value { get; set; }
///
/// Event for value changed
///
[Parameter]
public EventCallback ValueChanged { get; set; }
///
/// CssClass for input component
///
[Parameter]
public string CssClass { get; set; } = string.Empty;
///
/// Number of decimal places to display in percentage format.
/// Example: Decimals=2 → "15.00%".
///
[Parameter]
public int Decimals { get; set; } = 2;
///
/// If true, parsing is always done with InvariantCulture.
/// If false (default), try CurrentCulture first, then InvariantCulture.
///
[Parameter]
public bool ForceInvariantParsing { get; set; } = false;
///
/// Percentage format string
///
private string DisplayValue => Value.ToString($"P{Decimals}");
///
/// Change value event
///
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);
}
}
}