Принимать запятую и точку в виде десятичного разделителя
Связывание модели в ASP.NET MVC отлично, но оно следует за настройками локали. В моем локальном десятичном разделителе есть запятая (','), но пользователи также используют точку ('.'), Потому что они ленивы для переключения макетов. Я хочу, чтобы это реализовано в одном месте для всех полей decimal
в моих моделях.
Должен ли я реализовать свой собственный поставщик стоимости (или привязку Event Model) для типа decimal
или я пропустил какой-то простой способ сделать это?
Ответы
Ответ 1
Самый чистый способ - реализовать собственное связующее устройство
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
}
}
И зарегистрируйте его внутри Application_Start():
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
Кредиты: Стандартное связывание модели ASP.NET MVC 3 не связывает десятичные свойства
Ответ 2
Чтобы правильно обработать разделитель групп, просто замените
Convert.ToDecimal(valueProviderResult.AttemptedValue);
в выбранном ответе с помощью
Decimal.Parse(valueProviderResult.AttemptedValue, NumberStyles.Currency);
Ответ 3
Благодаря принятому ответу я закончил следующую реализацию для обработки float, double и decimal.
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;
}
Затем вам просто нужно установить свой ModelBinders на Application_Start
метод
ModelBinders.Binders[typeof(float)] = new SingleModelBinder();
ModelBinders.Binders[typeof(double)] = new DoubleModelBinder();
ModelBinders.Binders[typeof(decimal)] = new DecimalModelBinder();
Ответ 4
var nfInfo = new System.Globalization.CultureInfo(lang, false)
{
NumberFormat =
{
NumberDecimalSeparator = "."
}
};
Thread.CurrentThread.CurrentCulture = nfInfo;
Thread.CurrentThread.CurrentUICulture = nfInfo;