web-dev-qa-db-ja.com

小数点記号としてカンマとドットを受け入れます

ASP.NET MVCのモデルバインディングはすばらしいですが、ロケール設定に従います。私のロケールでは、小数点はカンマ( '、')ですが、レイアウトの切り替えが面倒なので、ドット( '。')も使用します。これを、モデルのすべてのdecimalフィールドの1つの場所に実装したいと考えています。

decimalタイプ用に独自の値プロバイダー(またはイベントモデルバインダー)を実装する必要がありますか、これを行う簡単な方法をいくつか見逃しましたか?

22
artvolk

最もクリーンな方法は、独自のモデルバインダーを実装することです

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モデルバインダーは10進数のプロパティをバインドしません

38
mathieu

グループセパレータを適切に処理するには、単に置き換えます

Convert.ToDecimal(valueProviderResult.AttemptedValue);

選択した回答で

Decimal.Parse(valueProviderResult.AttemptedValue, NumberStyles.Currency);
5
Miguel Veloso

受け入れられた回答のおかげで、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;
}

次に、Application_StartメソッドにModelBindersを設定するだけです

ModelBinders.Binders[typeof(float)] = new SingleModelBinder();
ModelBinders.Binders[typeof(double)] = new DoubleModelBinder();
ModelBinders.Binders[typeof(decimal)] = new DecimalModelBinder();
3
labilbe
var nfInfo = new System.Globalization.CultureInfo(lang, false)
{
    NumberFormat =
    {
        NumberDecimalSeparator = "."
    }
};
Thread.CurrentThread.CurrentCulture = nfInfo;
Thread.CurrentThread.CurrentUICulture = nfInfo;
2
Denis