0

だから私は辞書プロパティのリストを含むViewModelを持っています

public class ViewModel
{
    public List<Dictionary<int, bool>> Columns { get; set; }
}

ビューからこのモデルを取り戻そうとしていますが、常にnullアイテムのリストを返します。

@Html.Hidden(String.Format("Columns[{0}][{1}].Key", i, firstItem.Id), firstItem.Id)
@Html.CheckBox(String.Format("Columns[{0}][{1}].Value", i, firstItem.Id), Model.Columns[i][firstItem.Id])

これは機能しません。

@Html.CheckBoxFor(m => m.Columns[i][firstItem.Id])

これもうまくいきません。

私は何を間違っていますか?

4

1 に答える 1

1

ネストされたコレクションが含まれているため、ViewModel は非常に複雑です。デフォルトのモデル バインダーを使用して入力値をモデルにバインドする方法はないと思います。カスタム モデル バインダーを作成する必要があります。カスタム モデル バインダーを実装しようとしました。これが私の実装 ListDictionary モデル バインダーです。

カスタムモデルバインダー

    public class ListDictionaryModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var resultList = new List<Dictionary<int, bool>>();
            var forms = controllerContext.HttpContext.Request.Form;
            var regex = new Regex(@"(true,)?false");
            var result =
                forms.AllKeys.Select(x => new {key = x, value = forms[x]}).Where(x => x.key.Contains("Columns")).ToList();
            result.ForEach(x =>
                               {
                                   var matches = regex.Matches(x.value);
                                   var dictionary = new Dictionary<int, bool>();
                                   for (var i = 0; i < matches.Count; i++)
                                   {
                                       var value = matches[i].ToString() == "true,false" ? true : false;
                                       dictionary.Add(i, value);
                                   }
                                   resultList.Add(dictionary);
                               });
            return resultList;
        }
    }

使用例

コントローラ:

        public ActionResult Index()
        {
            //example data
            var viewModel = new ViewModel
                                      {
                                          Columns = new List<Dictionary<int, bool>>
                                                        {
                                                            new Dictionary<int, bool> {{1, false}, {2, false}},
                                                            new Dictionary<int, bool> {{1, false}, {2, false}}
                                                        }
                                      };

            return View(viewModel);
        }

        [HttpPost]
        public ActionResult Index(ViewModel viewModel)
        {
            //viewModel - contains values of user input
            return View();
        }

インデックス ビュー:

@model RepositoryTestProject.ViewModels.ViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>


@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>ViewModel</legend>


@Html.EditorFor(x => Model.Columns,"_ColumnEdit")

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

部分ビュー: (「/Views/Shared」に「EditorTemplates」フォルダーを作成し、部分テンプレートをフォルダーに配置する必要があります)

_ColumnEdit 部分ビュー:

@model List<Dictionary<int,bool>>

@for(int i =0; i < Model.Count();i++)
{
    @Html.EditorFor(x=>Model[i],"_DictEdit")
}

_DictEdit 部分ビュー:

@model Dictionary<int, bool>

@for(int i =0; i < Model.Count();i++)
{
    @Html.CheckBoxFor(x=>Model.ElementAt(i).Value)
}

global.asax にモデル バインダーを登録する必要があります

ModelBinders.Binders.Add(typeof(List<Dictionary<int,bool>>), new ListDictionaryModelBinder());

最後に、次のようにコントローラーで値を取得できます。

ここに画像の説明を入力

于 2012-11-01T07:19:49.163 に答える