私が持っているとしましょう
class FooClass { }
class BarClass
{
public FooClass Foo;
}
このBarClassは、ViewPageに渡すモデルです。
また、(ViewDataを介して)IEnumerable<SelectListItem>
すべてのFooを含むを渡し、それに一致するものbar.Foo
を選択します(実行時にチェックされます)。
私はそれから呼んでいますHtml.DropDownList("Foo", foos);
ドロップダウンリストは適切にレンダリングされますが、htmlコントロールにプロパティの名前があり、ViewData.Eval()
内部で実行されるを混乱させるため、適切なアイテムが選択されません。それは受け入れられた振る舞いのようです(SOでそれについて多くの答えを見ました)ので、私はそれについて議論しておらず、拡張機能への呼び出しを次のように変更します:
Html.DropDownList("DDL_Foo", foos);
適切な値が選択され、私は満足しています。だから私はフォームを送り返します。
悲しいことに、私のコントローラーの適切なアクションでは、Fooメンバーはnullです。そこで、フォームのDDL_Fooをインターセプトし、FooClassを適切に初期化するためのFooModelBinder
実装を追加します。IModelBinder
しかし、FooModelBinder.BindModel
決して解雇さbar.Foo
れることはなく、nullです。ビューを再度変更し、ドロップダウンリストの名前をFooに戻すと、FooModelBinderが期待どおりに起動し、bar.Fooが正常に初期化されます。
それで、私は何を逃しましたか?そしてもっと重要なのは、それを適切な方法でどのように行うべきかということです。私はたくさんのハックとその回避策を考え出しましたが、それは私が探しているものではありません。私はそれを正しく行う方法を知りたいです。
ありがとうございました!
[編集] フィードバックありがとうございますが、プレフィックスが問題になるとは思いません。
バインダーについては、正しく初期化できないので追加しました。私が取り組んでいる実際のケースは、ここに示されているものよりもはるかに複雑であることに注意してください。このソリューションは、問題を再現するために実行できる最小のモックアップです。
ここでそれは尋ねられた啓示的なコードです(または完全な解決策をダウンロードしてください):
コントローラ
[HttpGet]
public ActionResult Index()
{
var dp = new DummyProvider();
var bar = dp.GetBar();
var foos = new List<SelectListItem>();
dp.GetAllFoos().ForEach(
f => foos.Add(new SelectListItem {Text = f.Name, Value = f.Id.ToString(), Selected = f.Id == bar.Foo.Id }));
ViewData["foos"] = foos;
return View(bar);
}
[HttpPost]
public ActionResult Index(BarClass bar)
{
var dp = new DummyProvider();
var foos = new List<SelectListItem>();
dp.GetAllFoos().ForEach(
f => foos.Add(new SelectListItem { Text = f.Name, Value = f.Id.ToString(), Selected = f.Id == bar.Foo.Id }));
ViewData["foos"] = foos;
ViewData["selectedItem"] = bar.Foo.Name;
return View(bar);
}
見る
<%
var foos = ViewData["foos"] as List<SelectListItem>;
using(Html.BeginForm())
{
%>
<p>
<h3>Enter Another Value</h3>
<%= Html.TextBox("AnotherValue", Model.AnotherValue) %>
</p>
<p>
<h3>Enter Yet Another Value</h3>
<%= Html.TextBox("YetAnotherValue", Model.YetAnotherValue) %>
</p>
<p>
<h3>Choose a foo</h3>
<%= Html.DropDownList("DDL_Foo", foos)%>
</p>
<button type="submit">Send back !</button>
<%
}
%>
モデル
public class BarClass
{
public FooClass Foo { get; set; }
public string AnotherValue { get; set; }
public string YetAnotherValue { get; set; }
}
public class FooClass
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class FooClassCollection : List<FooClass> { }
public class FooModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var foo = new FooClass();
var guid = Guid.Empty;
if (Guid.TryParse(controllerContext.HttpContext.Request.Form["DDL_Foo"], out guid))
{
foo.Id = guid;
}
return foo;
}
}
public class DummyProvider
{
public FooClassCollection GetAllFoos()
{
return new FooClassCollection
{
new FooClass {Name = "Item 1", Id = new Guid("4a402abd-ab85-4065-94d6-d9fcc0f9b69e")},
new FooClass {Name = "Item 2", Id = new Guid("cf20bfd6-0918-4ffc-a6ec-c4cc4ed30e7f")},
new FooClass {Name = "Item 3", Id = new Guid("ad81b882-b93e-42b9-a42c-78376dd8f59d")},
new FooClass {Name = "Item 4", Id = new Guid("1511c15d-9ae4-4b18-9e10-e02588c21b27")},
new FooClass {Name = "Item 5", Id = new Guid("855e4a2f-fc5b-4117-a888-1dc3ebb990fc")},
};
}
public BarClass GetBar()
{
return new BarClass
{
AnotherValue = "Nice value",
YetAnotherValue = "This one is awesome",
Foo = new FooClass {Name = "Item 3", Id = new Guid("ad81b882-b93e-42b9-a42c-78376dd8f59d")}
};
}
}
GLOBAL.ASAX
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(FooClass), new FooModelBinder());
}
[編集] codeplexには未解決の問題があります。解決したい場合は、投票してください(1年近く開いていたとしても)。