La liaison de modèle dans ASP.NET MVC est excellente, mais elle suit les paramètres régionaux. Dans ma région, le séparateur décimal est une virgule (','), mais les utilisateurs utilisent également le point ('.'), Car ils sont paresseux pour changer de disposition. Je veux que cela soit implémenté en un seul endroit pour tous les champs decimal
dans mes modèles.
Dois-je implémenter mon propre fournisseur de valeur (ou classeur de modèle d'événement) pour le type decimal
ou j'ai manqué un moyen simple de le faire?
Le moyen le plus propre consiste à implémenter votre propre classeur de modèle
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) : Convert.ToDecimal(valueProviderResult.AttemptedValue);
// of course replace with your custom conversion logic
}
}
Et enregistrez-le dans Application_Start ():
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
Crédits: le classeur de modèle ASP.NET MVC 3 par défaut ne lie pas les propriétés décimales
Pour gérer correctement le séparateur de groupe, remplacez simplement
Convert.ToDecimal(valueProviderResult.AttemptedValue);
dans la réponse sélectionnée avec
Decimal.Parse(valueProviderResult.AttemptedValue, NumberStyles.Currency);
Grâce à la réponse acceptée, je me suis retrouvé avec l'implémentation suivante pour gérer flottant, double et décimal.
public abstract class FloatingPointModelBinderBase<T> : DefaultModelBinder
{
protected abstract Func<string, IFormatProvider, T> ConvertFunc { get; }
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null) return base.BindModel(controllerContext, bindingContext);
try
{
return ConvertFunc.Invoke(valueProviderResult.AttemptedValue, CultureInfo.CurrentUICulture);
}
catch (FormatException)
{
// If format error then fallback to InvariantCulture instead of current UI culture
return ConvertFunc.Invoke(valueProviderResult.AttemptedValue, CultureInfo.InvariantCulture);
}
}
}
public class DecimalModelBinder : FloatingPointModelBinderBase<decimal>
{
protected override Func<string, IFormatProvider, decimal> ConvertFunc => Convert.ToDecimal;
}
public class DoubleModelBinder : FloatingPointModelBinderBase<double>
{
protected override Func<string, IFormatProvider, double> ConvertFunc => Convert.ToDouble;
}
public class SingleModelBinder : FloatingPointModelBinderBase<float>
{
protected override Func<string, IFormatProvider, float> ConvertFunc => Convert.ToSingle;
}
Ensuite, il vous suffit de définir vos ModelBinders sur Application_Start
méthode
ModelBinders.Binders[typeof(float)] = new SingleModelBinder();
ModelBinders.Binders[typeof(double)] = new DoubleModelBinder();
ModelBinders.Binders[typeof(decimal)] = new DecimalModelBinder();
var nfInfo = new System.Globalization.CultureInfo(lang, false)
{
NumberFormat =
{
NumberDecimalSeparator = "."
}
};
Thread.CurrentThread.CurrentCulture = nfInfo;
Thread.CurrentThread.CurrentUICulture = nfInfo;