6

カスタムタイプのモデルバインダーがありますMoney。バインダーは正常に機能しますが、組み込みのバインディング/検証が開始され、データが無効としてマークされます。

私のバインダーは次のようになります:

public class MoneyModelBinder : DefaultModelBinder 
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var money = (Money)bindingContext.Model;
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Amount").AttemptedValue;
        var currencyCode = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Iso3LetterCode").AttemptedValue;

        Money parsedValue;
        if (String.IsNullOrEmpty(value))
        {
            money.Amount = null;
            return;
        }

        var currency = Currency.FromIso3LetterCode(currencyCode);

        if(!Money.TryParse(value, currency, out parsedValue))
        {
            bindingContext.ModelState.AddModelError("Amount", string.Format("Unable to parse {0} as money", value));
        }
        else
        {
            money.Amount = parsedValue.Amount;
            money.Currency = parsedValue.Currency;
        }
    }
}

ユーザーが「45,000」などの値をテキストボックスに入力すると、バインダーはその値を正しく取得し、解析してモデルに設定します。

私が抱えている問題は、デフォルトの検証が状態The value '45,000' is not valid for Amountで開始されることです。これは10進型であるため意味がありますが、データはすでにバインドされています。すでに処理したデータをバインドするデフォルトのバインダーを防ぐにはどうすればよいですか?

これが違いを生むかどうかはわかりませんがHtml.EditorFor、次のようなエディターを使用しています。

@model Money

<div class="input-prepend">
  <span class="add-on">@Model.Currency.Symbol</span>
    @Html.TextBoxFor(m => m.Amount, new{
                            placeholder=string.Format("{0}", Model.Currency), 
                            @class="input-mini",
                            Value=String.Format("{0:n0}", Model.Amount)
                            })
    @Html.HiddenFor(x => x.Iso3LetterCode)
</div>
4

3 に答える 3

5

Amountプロパティを読み取り専用としてマークするだけです。

[ReadOnly(true)]
public decimal? Amount { get; set; }
于 2012-11-18T18:53:34.443 に答える
2

ModelBinderコードが同じプロジェクトにある場合は、プロパティセッターのアクセス修飾子をinternalに変更できます。このように、DefaultModelBinderはセッターを認識できませんでした。

public class MyViewModel{
 public Money Stash { get; internal set; }
}

別の方法は、単にフィールドの使用法である可能性があります

public class MyViewModel{
 public Money Stash;
}

この背後にある理由は、DefaultModelBinderが読み取り/書き込みプロパティのみをバインドすることです。上記の両方の提案は、これらの条件が満たされるのを防ぎます。

于 2012-11-17T02:02:14.787 に答える
1

私の経験からこれを行うにはいくつかの方法があります(たとえば、デフォルトのバインダーをバインドできるようにしますが、プロパティのエラーをクリアします)が、コードを維持している人にあなたの意図を明確にするこれを行う方法は、オーバーライドすることです望ましくない動作、すなわち:

protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
    if (propertyDescriptor.Name != "Amount")
    {
        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }
}

ここのelseブロックで実際にカスタムバインディングを実行することも理にかなっているかもしれませんが、それはあなたが決めることです。

于 2012-11-18T05:36:04.703 に答える