当前正在尝试重新设计 .NET 4.8 MVC 应用程序以支持全球化(需要支持英语和法语)。到目前为止,一切都很顺利。
然而,问题在于十进制输入。这是一个财务应用程序,因此处理设置为
type="number"
的输入框非常重要。严格来说,我知道值 15000,25
不被视为数字,并且不会隐式转换为小数(我在视图模型中使用的支持字段数据类型)。考虑到这一点,我有一个自定义模型活页夹:
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null)
{
return base.BindModel(controllerContext, bindingContext);
}
if (string.IsNullOrEmpty(valueProviderResult.AttemptedValue))
{
return null;
}
var result = decimal.TryParse(valueProviderResult.AttemptedValue, NumberStyles.Currency, CultureInfo.InvariantCulture, out decimal covertedOutput);
if (result)
{
return covertedOutput;
}
return null;
}
}
然后将该模型绑定器注册到 Global.asax 文件中。上面的内容似乎在一定程度上有效......特别是在 Firefox 中,因为我可以在表单输入中输入 15000,25,而后端发生的情况是 15000.25 记录在数据库中。
这是 chrome 中的一个不同的故事,因为
指定值“15000,25”无法解析,或者超出范围
我的问题是这样的 - 我应该强迫用户始终处理真正的基于十进制的数字吗?那么阻止他们输入 15000,25 但允许 15000.25 呢?还是有一种我没有看到的解决方法/最佳实践?
这是我正在使用的小数字段。表单控件和视图模型属性:
@Html.TextBoxFor(model => model.SellAmount, "{0:f2}", new {min = "0", type = "number", step = "1000" })
public decimal? SellAmount { get; set; }
因此,通过进行大量研究,我设法想出了一个解决方案。
我遇到的一个问题是,浏览器会在视图重新渲染期间尝试将其自己的本地化值插入到文本框中。这会导致 chrome 引发以下错误:
指定值“{value}”无法解析,或超出范围
为了防止这种情况发生,我扩展了MVC输入控件:
public static class InputExtensions
{
public static MvcHtmlString NumberInput<TModel, TProperty>(this HtmlHelper<TModel> helper
, Expression<Func<TModel, TProperty>> expression, string format = null)
{
// Get decimal value from the model
var value = (decimal)ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
// Render the input, this stops the browser from inserting it's own 'localized' format
helper.TextBoxFor(expression, format, new { pattern = @"[0-9]+([\.][0-9]{1,2})?", @Value = value });
}
}
您只需从视图中调用分机即可:
@Html.NumberInput(model => model.Input.SellAmount, "{0:f2}")
执行上述操作意味着我可以强制用户使用 000.00 格式的小数,在其他地方,我只是让 UICulture 在显示值(在标签等中)时接管
这解决了我遇到的很多本地化问题。