使用复选框绑定到具有强类型 MVC 视图的布尔列表列表字典

2023-11-27

我正在使用 MVC 4、.Net 4 和 Visual Studio 2012。

我正在尝试将一个相当复杂的模型与我的观点之一结合使用,但在使其正确绑定方面遇到了严重的困难。

该模型用整数键和布尔列表列表值来包装字典。

基本上,搜索是对由整数指示的项目进行的,每个项目都有几个搜索词,对于每个词我们都有一个结果列表。我将结果显示在页面上,并且每个结果旁边都有一个复选框。对于每个结果,用户将通过选中该框来指示他们是否希望下一个操作完成某些操作。

目前,复选框正确显示,包括来自控制器的预设值,但是当我按下表单底部的提交按钮时,出现此错误:

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.aspx, or asp.net mvc 中复杂类型的复选框列表, or 如何在 ASP.NET MVC 上为 GET 和 POST 操作绑定字典类型参数,但我在写完问题后发现了这些,但我还没有弄清楚,所以也许有人可以帮助我。

这是堆栈跟踪的顶部:

[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; }
    }

以下是视图中的一些相关部分,其中变量名称已更改以保护无辜者:

@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>
}

好吧,我明白了。

我尝试使用 Tuple>> 而不是 Dictionary>> 。那失败了,显然是因为 Tuple 没有 0 参数构造函数。

然后,我尝试使用具有两个属性的自定义类:一个 int 和一个 List>。经过一番摆弄之后,我让它开始工作,一旦工作成功,我就能够对其进行逆向工程,并使字典开始工作。

这是工作版本(与以前相同的视图模型和 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++;

}

...

因此,字典键的隐藏输入上使用的索引不是键,而是键值对的枚举,第 0 个、第 1 个、第 2 个,依此类推。这与稍后用于指示值的索引相同。

这引出了另一个有趣的部分。复选框的名称需要包含 Model.DictionaryName[enumerationIndex].Value 以指示我们正在为该索引的 KeyValue 对设置值。

此外,该辅助函数生成的 html 输入元素的值始终为 true,而第二个隐藏输入的值始终为 false。 “checked”属性指示输入复选框的值是否发送到默认绑定器,即它是否获取“true、false”值或仅“false”值。然后绑定器将其正确解释为布尔值。

最后,最后的 else 块中的隐藏输入为没有匹配搜索结果的条目添加一个空 List> 。 .Value 与之前的 .Key 配对,指示要添加到字典中的完整 KeyValue 对。然后,当绑定器看到 Model.Dictionary[index].Value[index] 而没有看到 Model.Dictionary[index].Value[index][index] 时,它会创建一个空列表,但不会添加任何值。

所以这不必要地复杂,但现在希望其他人可以在他们的 ViewModel 中使用带有 Collection 值的字典。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用复选框绑定到具有强类型 MVC 视图的布尔列表列表字典 的相关文章