加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 使用Checkboxes绑定到具有强类型MVC视图的Bools

发布时间:2020-12-16 07:12:40 所属栏目:asp.Net 来源:网络整理
导读:我正在使用MVC 4,.Net 4和Visual Studio 2012. 我正在尝试使用一个相当复杂的模型与我的一个观点,我遇到了严重的麻烦,让它正确绑定. 该模型使用整数键包装一个Dictionary,并将值列为bools列表. 基本上,搜索是在整数表示的项目上进行的,每个项目都有几个搜索
我正在使用MVC 4,.Net 4和Visual Studio 2012.

我正在尝试使用一个相当复杂的模型与我的一个观点,我遇到了严重的麻烦,让它正确绑定.

该模型使用整数键包装一个Dictionary,并将值列为bools列表.

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

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

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,或Checkbox list for complex type in asp.net mvc,或How 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,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< int,List< List< bool>>>而不是字典< int,List< List< bool>>>.那失败了,显然是因为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”的值.然后,粘合剂将其正确解释为bool值.

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读