5

ビュー モデルの一部のdecimalおよびdecimal?プロパティは、他のデータ注釈とともに「パーセント」データ型としてマークされています。次に例を示します。

[DataType("Percent")]
[Display(Name = "Percent of foo completed")]
[Range(0, 1)]
public decimal? FooPercent { get; set; }

ユーザーがデータを入力する方法にある程度の柔軟性を持たせたいと思います。つまり、パーセント記号、中間スペースなどの有無にかかわらず、動作を使用して、チェックや追加DefaultModelBinderなどのすべての機能を取得したいRangeAttribute適切な検証メッセージ。

モデル値を解析して変更し、それを渡す方法はありますか? これが私が試みていることですが、実行時例外が発生しています。(実際の解析ロジックは無視してください。これは最終的な形式ではありません。この時点でモデル置換の問題に興味があるだけです。)

public class PercentModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,
                                     ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelMetadata.DataTypeName == "Percent")
        {
            ValueProviderResult result =
                bindingContext.ValueProvider.GetValue(
                    bindingContext.ModelName);
            if (result != null)
            {
                string stringValue =
                    (string)result.ConvertTo(typeof(string));
                decimal decimalValue;
                if (!string.IsNullOrWhiteSpace(stringValue) &&
                    decimal.TryParse(
                        stringValue.TrimEnd(new char[] { '%', ' ' }),
                        out decimalValue))
                {
                    decimalValue /= 100.0m;

                    // EXCEPTION : This property setter is obsolete, 
                    // because its value is derived from 
                    // ModelMetadata.Model now.
                    bindingContext.Model = decimalValue;
                }
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}
4

1 に答える 1

5

気にしないでください。これは、MVC サイクルのどこで検証が行われるかについての根本的な誤解でした。MVC のソース コードを少し調べてみると、これがどのように機能するかがわかります。

他の人に役立つ場合は、ここに私のために働いているものがあります:

[DataType("Percent")]
[Display(Name = "Percent of foo completed")]
[Range(0.0d, 1.0d, ErrorMessage="The field {0} must be between {1:P0} and {2:P0}.")]
public decimal? FooPercent { get; set; }

バインダーでは、値を返すだけです。

public class PercentModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,
                                     ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelMetadata.DataTypeName == "Percent")
        {
            ValueProviderResult result =
                bindingContext.ValueProvider.GetValue(
                    bindingContext.ModelName);
            if (result != null)
            {
                string stringValue =
                    (string)result.ConvertTo(typeof(string));
                decimal decimalValue;
                if (!string.IsNullOrWhiteSpace(stringValue) &&
                    decimal.TryParse(
                        stringValue.TrimEnd(new char[] { '%', ' ' }),
                        out decimalValue))
                {
                    return decimalValue / 100.0m;
                }
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}
于 2012-01-04T16:43:37.337 に答える