2011-04-14 70 views
1

DropDownLists可能是我最不喜歡使用MVC框架的部分。我的表單中有幾個下拉列表,我需要將選定的值傳遞給接受模型作爲其參數的ActionResult。MVC DropDownList值發佈到模型沒有綁定

的標記看起來是這樣的:

<div class="editor-label"> 
    @Html.LabelFor(model => model.FileType) 
</div> 
<div class="editor-field"> 
    @Html.DropDownListFor(model => model.FileType.Variety, (SelectList)ViewBag.FileTypes) 
</div> 

<div class="editor-label"> 
    @Html.LabelFor(model => model.Status) 
</div> 
<div class="editor-field"> 
    @Html.DropDownListFor(model => model.Status.Status, (SelectList)ViewBag.Status) 
</div> 

我的控制器操作是這樣的:

[HttpPost] 
public ActionResult Create(int reviewid, ReviewedFile file) 
{ 
    if (ModelState.IsValid) 
    { 
     UpdateModel(file); 
    } 

    //repository.Add(file); 

    return RedirectToAction("Files", "Reviews", new { reviewid = reviewid, id = file.ReviewedFileId }); 
} 

這應該是所有好,除了從下拉菜單中的值好被張貼空值。當我深入瞭解一下的ModelState錯誤,原因是發現:

從類型 「System.String」輸入 「PeerCodeReview.Models.OutcomeStatus」 參數轉換失敗,因爲沒有類型轉換器可 在這些類型之間進行轉換。

它不應該這麼難,但它是。所以問題是,我需要做什麼才能正確地綁定我的模型屬性?另外,我知道我可以傳遞一個FormCollection對象,但這意味着要更改當前期望強類型模型參數的單元測試的重要部分。

+0

此外,你不需要說的UpdateModel(文件)在那裏,張貼表單值已經包含在你的'ReviewedFile file'參數。 – 2011-04-14 03:10:32

+0

我只是需要它來檢查ModelState錯誤。一旦我弄清楚如何排除問題,我們就會去做。 – 2011-04-14 04:18:48

回答

2

試試這個:

<div class="editor-label"> 
    @Html.LabelFor(model => model.FileType) 
</div> 
<div class="editor-field"> 
    @Html.DropDownListFor(model => model.FileType.Id, (SelectList)ViewBag.FileTypes) 
</div> 

<div class="editor-label"> 
    @Html.LabelFor(model => model.Status) 
</div> 
<div class="editor-field"> 
    @Html.DropDownListFor(model => model.Status.Id, (SelectList)ViewBag.Status) 
</div> 
+0

很好的建議,但我已經嘗試過了,同樣的錯誤仍然存​​在 - MVC不知道如何將字符串值轉換爲相應的對象屬性(例如,評論文件.FileType) – 2011-04-14 04:24:36

+0

我不能重複這一點。我已經設置了一個快速項目並模仿了你的類,但是MVC將字符串值轉換爲對象屬性。例如,如果我進入Create操作並檢查file.FileType的值,那麼我得到一個'FileType'類型的對象,其值爲'{Id = 2,Variety = null}'。它可能不是完整的對象,但有足夠的信息從回購中檢索它。它究竟爲你做了什麼? – 2011-04-14 13:16:26

3

您需要爲綁定到下拉列表的兩個屬性創建並註冊自定義模型聯編程序。

這裏是我的模型綁定我建了整整爲此代碼:

public class LookupModelBinder<TModel> : DefaultModelBinder 
    where TModel : class 
{ 
    private string _key; 

    public LookupModelBinder(string key = null) 
    { 
     _key = key ?? typeof(TModel).Name; 
    } 

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var dbSession = ((IControllerWithSession)controllerContext.Controller).DbSession; 

     var modelName = bindingContext.ModelName; 
     TModel model = null; 
     ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (vpResult != null) 
     { 
      bindingContext.ModelState.SetModelValue(modelName, vpResult); 
      var id = (int?)vpResult.ConvertTo(typeof(int)); 
      model = id == null ? null : dbSession.Get<TModel>(id.Value); 
     } 
     if (model == null) 
     { 
      ModelValidator requiredValidator = ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata, controllerContext).Where(v => v.IsRequired).FirstOrDefault(); 
      if (requiredValidator != null) 
      { 
       foreach (ModelValidationResult validationResult in requiredValidator.Validate(bindingContext.Model)) 
       { 
        bindingContext.ModelState.AddModelError(modelName, validationResult.Message); 
       } 
      } 
     } 
     return model; 
    } 
} 

TModel是下拉框應綁定到屬性的類型。在我的應用程序中,下拉框給出數據庫中對象的Id,因此此模型綁定器將使用該ID,從數據庫中檢索正確的實體,然後返回該實體。您可能有不同的方式將由下拉列表給出的字符串轉換爲模型的正確實體。

您還需要在Global.asax中註冊模型聯編程序。

binders[typeof(EmploymentType)] = new LookupModelBinder<EmploymentType>(); 

這假設下拉列表控件的名稱與類型名稱相同。如果沒有,您可以將密鑰傳遞給模型聯編程序。

binders[typeof(EmploymentType)] = new LookupModelBinder<EmploymentType>("ControlName"); 
+0

+1用於自定義活頁夾。那個石頭。 – Farray 2011-07-12 21:44:19