2012-07-26 16 views
18

如果之前已詢問過,請致歉;有一百萬種方式來表達它,因此尋找答案已證明很困難。MVC3 - 帶有複雜類型列表的Viewmodel

我有以下屬性的視圖模型:

public class AssignSoftwareLicenseViewModel 
{ 
    public int LicenseId { get; set; } 
    public ICollection<SelectableDeviceViewModel> Devices { get; set; } 
} 

SelectableDeviceViewModel的簡化版本是這樣的:

public class SelectableDeviceViewModel 
{ 
    public int DeviceInstanceId { get; set; } 
    public bool IsSelected { get; set; } 
    public string Name { get; set; } 
} 

在我看來,我試圖顯示可編輯複選框列表對於Devices屬性,在輸入表單中。 目前,我的看法是這樣的:

@using (Html.BeginForm()) 
{ 
    @Html.HiddenFor(x => Model.LicenseId) 
    <table> 
     <tr> 
      <th>Name</th> 
      <th></th> 
     </tr> 
     @foreach (SelectableDeviceViewModel device in Model.Devices) 
     { 
      @Html.HiddenFor(x => device.DeviceInstanceId) 
      <tr> 
       <td>@Html.CheckBoxFor(x => device.IsSelected)</td> 
       <td>@device.Name</td> 
      </tr> 
     } 
    </table> 

    <input type="submit" value="Assign" /> 
} 

的問題是,當模型被調回控制器,設備爲空。

我的假設是,這是因爲即使我正在編輯它的內容,Devices屬性永遠不會明確包含在窗體中。我試圖用HiddenFor來包含它,但是這只是導致模型有一個空列表而不是null。

任何想法我在這裏做錯了嗎?

+0

你能告訴我們你的控制器代碼是填充數據模型嗎? – nikeaa 2012-07-26 21:26:31

+2

+1爲覆蓋此區域最優雅的問題。相信我,我們花了最近2個小時尋找這個問題! – 2012-10-11 12:28:56

回答

30

我的假設是,這種情況正在發生,因爲即使我 編輯其內容的設備的屬性是從來沒有明確 列入表格。

不,您的假設是錯誤的。沒有被正確綁定的原因是因爲您的輸入字段沒有正確的名稱。例如,他們被稱爲name="IsSelected"而不是name="Devices[0].IsSelected"。看看需要用於綁定到系列的正確線路格式:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

但是爲什麼會發生這種情況?

這是因爲您在視圖中使用的foreach循環。您使用x => device.IsSelected作爲複選框的lambda表達式,但這根本不考慮Devices屬性(正如您可以通過查看生成的網頁源代碼所看到的那樣)。

那麼我該怎麼做?

就個人而言,我會建議您使用編輯器模板,因爲他們尊重複雜屬性的導航上下文並生成正確的輸入名稱。所以擺脫你的整個視foreach循環,並用一行代碼替換它:

@Html.EditorFor(x => x.Devices) 

現在定義將自動ASP.NET MVC爲的每個元素呈現的自定義編輯模板設備集合。警告:此模板的位置和名稱都爲這個非常重要的工作原理是慣例:~/Views/Shared/EditorTemplates/SelectableDeviceViewModel.cshtml

@model SelectableDeviceViewModel 
@Html.HiddenFor(x => x.DeviceInstanceId) 
<tr> 
    <td>@Html.CheckBoxFor(x => x.IsSelected)</td> 
    <td>@Html.DisplayFor(x => x.Name)</td> 
</tr> 

另一種方法(我不推薦)是改變你目前的ICollection在你的視圖模型到索引集合(如IList<T>或陣列T[]):

public class AssignSoftwareLicenseViewModel 
{ 
    public int LicenseId { get; set; } 
    public IList<SelectableDeviceViewModel> Devices { get; set; } 
} 

,然後代替的foreach使用for環:

@for (var i = 0; i < Model.Devices.Count; i++) 
{ 
    @Html.HiddenFor(x => x.Devices[i].DeviceInstanceId) 
    <tr> 
     <td>@Html.CheckBoxFor(x => x.Devices[i].IsSelected)</td> 
     <td>@Html.DisplayFor(x => x.Devices[i].Name</td> 
    </tr> 
} 
+1

編輯器模板完美工作;非常感謝! – InsqThew 2012-07-27 14:56:28

+1

很好的答案,但爲什麼不建議在視圖模型中使用索引集合? – 2012-09-16 12:30:08

+1

@JamieIde,因爲我更喜歡使用編輯器模板。爲什麼在框架中已經考慮到了這些問題時,在視圖中編寫循環? – 2012-09-16 12:40:17

0

EditorFor模板工作,保持代碼乾淨。您不需要循環,模型會正確回傳。

但是,是否有人在複雜視圖模型(嵌套EditorFor模板)上驗證有問題?我使用Kendo Validator,並且遇到各種jquery錯誤。