2013-06-04 26 views
4

我使用MVC 4,.NET 4中,和Visual Studio 2012綁定到BOOLS一個強類型MVC視圖列表的列表的詞典使用複選框

我試圖使用相當複雜的模型與我的觀點之一,我很難讓它正確地綁定。

該模型使用整數鍵和字典列表的bools列表包裝字典。

基本上,對整數表示的項目進行搜索,每個項目都有幾個搜索項,對於每個項目,我們都有一個結果列表。我在頁面上顯示結果,並在每個結果旁邊都有一個複選框。對於每個結果,用戶將通過選中該框來指示他們是否想通過下一個操作完成某些內容。

目前,該複選框正常顯示,包括從控制器的預設值,但是當我按在窗體底部提交按鈕,我得到這個錯誤:

Specified cast is not valid. 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidCastException: Specified cast is not valid. 

這似乎我有一些關於使用字典的問題,據我所知,字典不適合作爲模型。我可能不得不改變其他的東西,但我寧願不去,除非我絕對必須。好像這裏可能有一個答案:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspxCheckbox list for complex type in asp.net mvcHow to bind Dictionary type parameter for both GET and POST action on ASP.NET MVC,但是我發現那些問題都寫完了,我還沒有弄清楚,所以也許有人可以幫我一把。

這裏的堆棧跟蹤的頂部:

[InvalidCastException: Specified cast is not valid.] 
    System.Web.Mvc.CollectionHelpers.ReplaceDictionaryImpl(IDictionary`2 dictionary, IEnumerable`1 newContents) +131 

[TargetInvocationException: Exception has been thrown by the target of an invocation.] 
    System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) +0 
    System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) +92 
    System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +108 
    System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) +19 
    System.Web.Mvc.CollectionHelpers.ReplaceDictionary(Type keyType, Type valueType, Object dictionary, Object newContents) +178 

這裏的模型:

public class AutoResolveModel { 
    public Dictionary<int, List<List<bool>>> SelectedResults { get; set; } 

    public AutoResolveModel() { 
     SelectedResults = new Dictionary<int, List<List<bool>>>(); 
    } 
} 

,因爲它可能是相關的,這裏的ViewBag.iidToData的結構,其中包含的結果是顯示:

In the controller action: 

    var iidToData = new Dictionary<int, List<ItemSearchResult>>(); 
    ViewBag.iidToData = iidToData; 

Elsewhere: 

    public class ItemSearchResult { 
     public string C { get; set; } 
     public string S { get; set; } 
     public List<int> Ss { get; set; } 
     public List<int> Ks { get; set; } 
    } 

以下是視圖中變量名稱更改的一些相關部分d來保護無辜:

@model AutoResolveModel 

@{ 
    string machineID; 
    Submission subm; 
    tblSignatures sig; 
    ItemSearchResult result; 

    var dc = new CloudDataContext(); 
} 

@using(Html.BeginForm("MyAction", "MyController", new { p = (int?) ViewBag.l }, FormMethod.Post)) { 

    foreach(KeyValuePair<int, List<ItemSearchResult>> kv in ViewBag.iidToData) { 

     <input type="hidden" name="@("SelectedResults[ " + kv.Key + " ].Key")" value="@kv.Key" /> 

     ID = (
      ... 
     ).Single(); 

     <h3>Inventory Item @ID</h3> 

     for(int isr = 0; isr < kv.Value.Count(); isr++) { 

      result = kv.Value[ isr ]; 

      <h4>Searched for @result.S from @result.C</h4> 

      <table border="0"> 
       <tr><th>K</th><th>I</th><th>V</th><th>G</th><th>D</th><th>S</th><th>T</th></tr> 
       @for(int i = 0; i < result.Ks.Count(); i++) { 
        subm = (
         ... 
        ).FirstOrDefault(); 
        try { 
         sig = (
          ... 
         ).Single(); 
        } catch { 
         sig = null; 
        } 

        if(subm != null && subm.K != 0) { 

         <tr> 
          <td>@Html.CheckBoxFor(m => m.SelectedResults[kv.Key][isr][i])</td> 
          <td>@result.Ks[ i ]</td> 
          <td>@subm.i</td> 
          <td>@subm.v</td> 
          <td>@subm.g</td> 
          <td>@subm.d</td> 
          @if(sig != null) { 
           <td>@sig.S</td> 
           <td>@sig.T</td> 
          } else { 
           <td>N/A</td> 
           <td>N/A</td> 
          } 
         </tr> 
        } 
       } 
      </table> 
     } 
    } 

    <button type="submit">Search</button> 
} 
+0

審查我上面包含的鏈接,以及http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx後,我做了幾個變化: 環之前: \t INT kvInd = 0; \t 更改: \t 到: \t DCShannon

+0

And:'​​@ Html.CheckBoxFor(m => m.SelectedResults [kv.Key] [isr] [i])'To:'​​'但我仍然得到同樣的錯誤。該死。 – DCShannon

回答

6

好吧,我明白了。

我試圖用一個元組< INT,列表<列表<布爾>>>而不是字典< INT,列表<列表<布爾>>>。這失敗了,顯然是因爲Tuple沒有0參數的構造函數。

然後,我嘗試使用一個自定義類,它有兩個屬性,一個int和一個List < List < bool >>。我得到了一些擺弄後的工作,一旦工作,我就可以對其進行逆向工程並使字典正常工作。

這裏的工作版本(同一視圖模型和iidToData如前):

... 

@{ 
    string machineID; 
    Submission subm; 
    tblSignatures sig; 
    ItemSearchResult result; 

    int kvInd = 0; 

    var dc = new CloudDataContext(); 
} 

... 

foreach(KeyValuePair<int, List<ItemSearchResult>> kv in ViewBag.iidToData) { 

    ... 

    <input type="hidden" name="@("Model.SelectedResults[" + kvInd + "].Key")" value="@kv.Key" /> 

    for(int isr = 0; isr < kv.Value.Count(); isr++) { 

     ... 

     @if(result.Keytbls.Any()) { 

      for(int i = 0; i < result.Keytbls.Count(); i++) { 

       ... 

       <td>@Html.CheckBox("Model.SelectedResults[" + kvInd + "].Value[" + isr + "][" + i + "]", Model.SelectedResults[ kv.Key ][ isr ][ i ])</td> 

       ... 

     } else { 
      <tr><td><input type="hidden" name="@("Model.SelectedResults[" + kvInd + "].Value[" + isr + "]")" /></td></tr> 
     } 

     ... 
    } 

    kvInd++; 

} 

... 

所以,對字典的鍵隱藏輸入使用的指標是不是關鍵,而是替代的枚舉KeyValue對,第0個,第1個,第2個,等等。這是用於稍後指示值的相同索引。

這導致我們另一個有趣的部分。該複選框的名稱需要包含Model.DictionaryName [enumerationIndex] .Value以表明我們正在爲該索引的KeyValue對設置值。

另外,該輔助函數生成的html輸入元素的值始終爲true,而第二個隱藏輸入的值始終爲false。 「checked」屬性指示輸入複選框的值是否被髮送到默認聯編程序,即它是否獲得「true,false」或僅「false」的值。然後由binder作爲布爾值正確解釋。

最後,在最後的else塊中的隱藏輸入添加一個空List <名單<布爾> >對於沒有匹配的搜索結果條目。 .Value與先前的.Key配對,以指示要添加到字典中的完整KeyValue對。然後,當活頁夾看到Model.Dictionary [index] .Value [index]而沒有看到Model.Dictionary [index] .Value [index] [index]時,它會創建一個空列表,但不會添加任何值。

因此,這是不必要的複雜,但現在希望別人可以在他們的ViewModels中使用集合值的字典。

+1

你應該爲此獲得一枚獎章。 – RealityDysfunction