1

いくつかの特殊なケースでは、実行前に ID がわからないテキストボックスのリスト (n - n 関連付けを処理するため) が必要になります。このようなもの: http://screencast.com/t/YjIxNjUyNmU

その特定のサンプルでは、​​カウントをいくつかの「テンプレート」に関連付けようとしています。

ASP.Net MVC 1では、Dictionary ModelBinder をコーディングして、クリーンで直感的な HTML を作成しました。次のようなことが許可されました:

// loop on the templates
foreach(ITemplate template in templates)
{
        // get the value as text
        int val;
        content.TryGetValue(template.Id, out val);
        var value = ((val > 0) ? val.ToString() : string.Empty);

        // compute the element name (for dictionary binding)
        string id = "cbts_{0}".FormatMe(template.Id);
%>
        <input type="text" id="<%= id %>" name="<%= id %>" value="<%= value %>" />
        <label for="<%= id %>"><%= template.Name %></label>
        <br />

バインダーのコードは次のとおりです。

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    IDictionary<int, int> retour = new Dictionary<int, int>();

    // get the values
    var values = bindingContext.ValueProvider;
    // get the model name
    string modelname = bindingContext.ModelName + '_';
    int skip = modelname.Length;

    // loop on the keys
    foreach(string keyStr in values.Keys)
    {
        // if an element has been identified
        if(keyStr.StartsWith(modelname))
        {
            // get that key
            int key;
            if(Int32.TryParse(keyStr.Substring(skip), out key))
            {
                int value;
                if(Int32.TryParse(values[keyStr].AttemptedValue, out value))
                    retour.Add(key, value);
            }
        }
    }
    return retour;
}

ASP.Net MVC 2に渡すとき、問題はValueProviderがもはや辞書ではないことです。私が行ったように、値をループして解析する方法はありません。

そして、私はそうする他の方法を見つけられませんでした(知っているなら教えてください).

私は最終的に辞書をバインドする「標準」の方法に切り替えましたが、HTML は見苦しく、直観に反し (カウンターを使用してインデックスのないコレクションをループしますか??)、必要な動作とは異なり、すべての値が必要です (そしてそのASP.Net MVC で完全に機能しました 1)。

次のようになります。

int counter= 0;
// loop on the templates
foreach(ITemplate template in templates)
{
        // get the value as text
        int val;
        content.TryGetValue(template.Id, out val);
        var value = ((val > 0) ? val.ToString() : string.Empty);

        // compute the element name (for dictionary binding)
        string id = "cbts_{0}".FormatMe(template.Id);
        string dictKey = "cbts[{0}].Key".FormatMe(counter);
        string dictValue = "cbts[{0}].Value".FormatMe(counter++);
%>
        <input type="hidden" name="<%= dictKey %>" value="<%= template.Id %>" />
        <input type="text" id="<%= id %>" name="<%= dictValue %>" value="<%= value %>" />
        <label for="<%= id %>"><%= template.Name %></label>
        <br />

ModelStateコントローラーでは、「値が必要です」というエラーを回避するために、をだます必要があります。

public ActionResult Save(int? id, Dictionary<int, int> cbts)
{
    // clear all errors from the modelstate
    foreach(var value in this.ModelState.Values)
        value.Errors.Clear();

これは難しすぎます。私はすぐにこの種のバインディングを何度も使用する必要があり、おそらくいくつかの層の開発者がアプリケーションで作業する必要があります。

質問 :

  • それをより良くする方法を知っていますか?

私が必要としているのは、IMO は、より良い html を許可し、すべての値が必要であることを考慮しない辞書用の ModelBinder です。

4

2 に答える 2

2

MVC 2 で MVC 1 モデル バインダーを引き続き使用することは完全に自由です。最大の変更点は、モデル バインダーが IValueProvider に対してではなく、直接 Request.Form に対して行う必要があることです。そのコレクションを列挙して、特定のシナリオに必要なロジックを実行できます。

IValueProvider インターフェイスの目的は、データの取得元を抽象化することであり、汎用バインダー (DefaultModelBinder など) を対象としています。データが列挙可能であることが保証されていないため、IValueProvider 自体を IEnumerable にすることはできません。ただし、特定のシナリオ用の特定のバインダーがあり、データがフォームから来ていることが既にわかっている特定のケースでは、抽象化は不要です。

于 2010-05-26T18:56:27.220 に答える
0

この記事が役立つと思います - Dictionary Model Binder in ASP.NET MVC2 and MVC3

要するに、解決策は、MVC 2-3 で MVC 1 ValueProvider を模倣することです。

于 2011-03-04T12:32:41.780 に答える