2013-01-18 8 views
21

L'associazione modello in ASP.NET MVC è ottima, ma segue le impostazioni locali. Nel mio separatore decimale locale è la virgola (','), ma gli utenti usano anche punto ('.'), Perché sono pigri per cambiare layout. Lo voglio implementato in un posto per tutti i campi decimal nei miei modelli.Accetta virgola e punto come separatore decimale

Devo implementare il mio proprio Value Provider (o event Model Binder) per il tipo decimal o mi sono perso un modo semplice per farlo?

+0

La soluzione accettata non funziona in alcuni casi. Il seguente link ha una soluzione che funziona per tutti i casi: https://stackoverflow.com/a/5117441/1314276 –

risposta

35

modo più pulito è quello di implementare il proprio modello di raccoglitore

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 
    }  
} 

e registrarlo all'interno Application_Start():

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder()); 
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder()); 

Crediti: Default ASP.NET MVC 3 model binder doesn't bind decimal properties

+1

Dove mettere la classe DecimalModelBinder? –

+1

@ ИванБишевац Metto il mio in \ Common \ ModelBinders. –

+0

Convert.ToDecimal (valueProviderResult.AttemptedValue) funziona bene per la virgola, ma per punto il numero viene moltiplicato per 100. Suggerimenti? –

1
var nfInfo = new System.Globalization.CultureInfo(lang, false) 
{ 
    NumberFormat = 
    { 
     NumberDecimalSeparator = "." 
    } 
}; 
Thread.CurrentThread.CurrentCulture = nfInfo; 
Thread.CurrentThread.CurrentUICulture = nfInfo; 
+0

più. ti amo amico! –

5

Per gestire correttamente separatore di gruppo , basta sostituire

Convert.ToDecimal(valueProviderResult.AttemptedValue); 

in risposta selezionata con

Decimal.Parse(valueProviderResult.AttemptedValue, NumberStyles.Currency); 
+2

o NumberStyles. Qualsiasi se vuoi andare selvaggio. – user15741

2

Grazie alla risposta accettata ho finito con la seguente implementazione di gestire float, double e decimale.

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; 
} 

Poi basta impostare le ModelBinders su Application_Start metodo

ModelBinders.Binders[typeof(float)] = new SingleModelBinder(); 
ModelBinders.Binders[typeof(double)] = new DoubleModelBinder(); 
ModelBinders.Binders[typeof(decimal)] = new DecimalModelBinder();