Merge branch 'release/AddInputSpecialCompo'
This commit is contained in:
@@ -7,6 +7,7 @@ namespace EgwCoreLib.BlazorTest.Data
|
||||
public static Dictionary<string, string> MenuList { get; set; } = new()
|
||||
{
|
||||
{"TestPdfViewer", "Test PdfViewer"},
|
||||
{"TestInput", "Test Input Ext"},
|
||||
{"TestQrDisplay", "Test QrDisplay"},
|
||||
{"TestGraphCompo", "Test Graph Compo"},
|
||||
{"TestBarcodeReader", "Test Barcode Read"},
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
@page "/TestInput"
|
||||
|
||||
<PageTitle>TestInput</PageTitle>
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>Test Input Specializzati</h3>
|
||||
</div>
|
||||
<div class="card-body py-1">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="fs-4">
|
||||
Decimal
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<InputDecimal Decimals="0" Step="0.001M" CssClass="form-control form-control-lg text-end w-auto" @bind-Value="@DecimalValue"></InputDecimal>
|
||||
<span class="input-group-text">Decimal 0</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<InputDecimal Decimals="3" Step="0.001M" CssClass="form-control form-control-lg text-end w-auto" @bind-Value="@DecimalValue"></InputDecimal>
|
||||
<span class="input-group-text">Decimal 3</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="fs-4">
|
||||
Percentage
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<InputPercent CssClass="form-control form-control-lg text-end w-auto" @bind-Value="@PercValue" Decimals="0"></InputPercent>
|
||||
<span class="input-group-text">Percent P0</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<InputPercent CssClass="form-control form-control-lg text-end w-auto" @bind-Value="@PercValue" Decimals="2"></InputPercent>
|
||||
<span class="input-group-text">Percent P2</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<InputPercent CssClass="form-control form-control-lg text-end w-auto" @bind-Value="@PercValue" Decimals="2" ForceInvariantParsing="true"></InputPercent>
|
||||
<span class="input-group-text">Percent P2 Invariant</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private decimal DecimalValue = 0;
|
||||
private decimal PercValue = 0.123M;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
@using System.Globalization
|
||||
<input type="number"
|
||||
value="@FormattedValue"
|
||||
@onchange="OnChange"
|
||||
step="@Step.ToString(CultureInfo.InvariantCulture)"
|
||||
min="@(Min?.ToString(CultureInfo.InvariantCulture))"
|
||||
max="@(Max?.ToString(CultureInfo.InvariantCulture))"
|
||||
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>
|
||||
/// Numero di cifre decimali gestite
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int Decimals { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Step incremento
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public decimal Step { get; set; } = 0.001M;
|
||||
|
||||
/// <summary>
|
||||
/// Valore minimo ammesso
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public decimal? Min { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Valore massimo ammesso
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public decimal? Max { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CssClass for input component
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string CssClass { get; set; } = string.Empty;
|
||||
|
||||
private string FormattedValue => Value.ToString($"F{Decimals}", CultureInfo.InvariantCulture);
|
||||
|
||||
private async Task OnChange(ChangeEventArgs e)
|
||||
{
|
||||
if (decimal.TryParse(e.Value?.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out var parsed))
|
||||
{
|
||||
var rounded = Math.Round(parsed, Decimals);
|
||||
Value = rounded;
|
||||
await ValueChanged.InvokeAsync(rounded);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
namespace EgwCoreLib.Utils
|
||||
{
|
||||
public class DictUtils
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Comparatore equality obj dizionario
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="dict1"></param>
|
||||
/// <param name="dict2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool DictAreEqual<TKey, TValue>(Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue> dict2)
|
||||
{
|
||||
// Handle null cases
|
||||
if (dict1 == null || dict2 == null)
|
||||
return dict1 == dict2;
|
||||
|
||||
// Quick size check
|
||||
if (dict1.Count != dict2.Count)
|
||||
return false;
|
||||
|
||||
// Compare each key-value pair
|
||||
foreach (var kvp in dict1)
|
||||
{
|
||||
if (!dict2.TryGetValue(kvp.Key, out TValue value))
|
||||
return false; // Key missing in dict2
|
||||
|
||||
if (!EqualityComparer<TValue>.Default.Equals(kvp.Value, value))
|
||||
return false; // Value mismatch
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user