比方說,我有Asp.net MVC2 IModelBinder正試圖推動我堅果(以及隨後的)
class FooClass { }
class BarClass
{
public FooClass Foo;
}
這BarClass是我傳遞到的ViewPage模型。
我也通過(通過ViewData)一個IEnumerable<SelectListItem>
與所有的Foo,並匹配bar.Foo
被選中(在運行時檢查)。
然後我打電話Html.DropDownList("Foo", foos);
的下拉列表呈現很好,但它並沒有選擇合適的項目,因爲HTML控件有屬性的名稱,它與運行internaly的ViewData.Eval()
食堂。這似乎是一個公認的行爲(見有關如此多的答案),所以我並不認爲有關和呼叫更改爲擴展名:
Html.DropDownList("DDL_Foo", foos);
正確的價值選擇和我快樂。所以我把表格寄回。
不幸的是,在我的控制器的相應操作中,Foo成員爲空。所以我添加一個FooModelBinder
,它實現了IModelBinder
來攔截表單的DDL_Foo並正確地初始化FooClass。
但是FooModelBinder.BindModel
從不被解僱,bar.Foo
爲空。如果我再次更改我的視圖並將下拉列表重新命名爲Foo,則FooModelBinder會按預期觸發,並且bar.Foo會根據需要進行初始化。
那麼,我錯過了什麼?更重要的是,我該如何做到這一點。我想到了大量的黑客和解決方法,但這不是我想要的。我想知道如何做對。
謝謝!
[編輯] 感謝您的反饋,但我不認爲前綴是問題。
關於Binder,我添加它,因爲它不能被正確地初始化,否則。請注意,我正在處理的真實案例比這裏介紹的更復雜。這個解決方案只是我能做的最小的模型來重現問題。
這將在revelant代碼問(或download the full solution):
控制器
[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);
}
VIEW
<%
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開放,如果你想解決,請選它,請(即使它已經將近一年,現在已經開放)。
你應該發佈一些代碼。我的猜測是,你的命名在對象定義的某個地方是錯誤的,而你根本不需要自定義聯編程序。 – 2010-07-30 16:55:04
看看我的相關問題,它可能會幫助你http://stackoverflow.com/questions/2563685/need-help-using-the-defaultmodelbinder-for-a-nested-model有一個類似的問題,它證明了命名約定。 – Will 2010-07-30 17:14:21
感謝您的反饋。我按要求添加了代碼。 – 2010-07-30 20:14:09