2010-05-26 40 views
10

我再一次遇到了「這不應該是這個?*!#困難」的情況。綁定到MVC中的SelectList

問題:我想在MVC中使用表單來創建對象。該對象的其中一個元素是一組有限的選擇 - 完美的候選下拉列表。

但是,如果我在我的模型中使用SelectList,並在View中使用下拉列表,然後嘗試將模型發回到我的Create方法,則會出現錯誤「Missing Method Exception:No Parameterless constructor for this目的」。瀏覽MVC源代碼,似乎爲了綁定到模型,Binder必須能夠首先創建它,並且它不能創建SelectList,因爲它沒有默認的構造函數。

這裏的簡化代碼: 對於模型:

public class DemoCreateViewModel 
{ 
    public SelectList Choice { get; set; } 
} 

對於控制器:

// 
// GET: /Demo/Create 

public ActionResult Create() 
{ 
    DemoCreateViewModel data = new DemoCreateViewModel(); 
    data.Choice = new SelectList(new string[] { "Choice1", "Choice2", "Choice3" }); 
    ViewData.Model = data; 
    return View(); 
} 

// 
// POST: /Demo/Create 

[HttpPost] 
public ActionResult Create(DemoCreateViewModel form) 
{ 
    try 
    { 
     // TODO: Add insert logic here 

     return RedirectToAction("Index"); 
    } 
    catch 
    { 
     return View(); 
    } 
} 

而對於瀏覽:

<fieldset> 
    <legend>Fields</legend> 
    <%= Html.LabelFor(model => model.Choice) %> 
    <%= Html.DropDownListFor(model => model.Choice, Model.Choice) %> 
    <p> 
     <input type="submit" value="Create" /> 
    </p> 
</fieldset> 

現在,我知道我可以使這項工作回落10碼和踢球:繞過模型綁定並退回到FormCo我自己選擇並驗證和綁定所有的領域,但是必須有一個更簡單的方法。我的意思是,這只是一個簡單的要求。有沒有辦法在MVC ModelBinding體系結構中進行這項工作?如果是這樣,那是什麼?如果不是,怎麼樣?

編輯:好吧,我的臉上有雞蛋,但也許這會幫助別人。我做了一些更多的嘗試,並找到了一個似乎可行的簡單解決方案。

提供一個簡單的值(字符串或整數,取決於您選擇的列表值類型),並將其命名爲您綁定的模型元素。然後提供第二個元素作爲選擇列表,並將其命名爲其他內容。所以,我的模型變成了:

public class DemoCreateViewModel 
{ 
    public string Choice { get; set; } 
    public SelectList Choices { get; set; } 
} 

然後在視圖中DropDownListFor聲明變成:

<%= Html.DropDownListFor(model => model.Choice, Model.Choices) %> 

當我這樣做,提交按鈕正確結合的形式作出了串選擇的選擇,並將模型提交回第二個Create方法。

+0

感謝您發佈您的修復程序,我遇到過類似的問題,並且您的修改幫助 – Chris 2010-10-25 11:54:06

+0

難道您不能將它綁定到IEnumerable或ListList的SelectListItems嗎? – 2012-09-26 08:40:58

回答

5

這裏有一個辦法:

@Html.DropDownListFor(model => model.Choice, 
         ViewBag.Choices as SelectList, 
         "-- Select an option--", 
         new { @class = "editor-textbox" }) 

請注意,我用ViewBag包含我的SelectList。這樣,當您回發時,客戶端不會將整個選擇列表作爲模型的一部分發送到服務器。

在控制器代碼,你只需要設置視圖袋:

ViewBag.Choices = new SelectList(.... 
+1

*請注意,我使用ViewBag來包含我的SelectList。通過這種方式,當您回發時,客戶端不會將整個選擇列表作爲模型的一部分發送到服務器。*(1)它不會; (2)如果是這樣,使用ViewBag不會阻止它被髮布,它會阻止它綁定到模型。 – 2014-03-13 19:53:43

0

考慮不選擇列表的屬性爲您創造職位的行動不同的視圖模型:

  public class DemoCreateViewModelForUpdate 
      { 
       public string Choice { get; set; } 
      } 

然後你就可以如果模型狀態無效且您想要重新顯示視圖,則始終將DemoCreateViewModelPost實例映射到DemoCreateViewModel實例。我傾向於將視圖所需的所有內容都放在我的顯示視圖模型類中,因此使用單獨的僅更新視圖模型讓我可以將事情保持苗條並修剪以便返回到服務器。

在你看來,你會怎麼做:

  @Html.DropDownListFor(m => m.Choice, Model.Choices) 

如前面的答案,所以沒有不必要的數據將往返。