Bind to a Dictionary of Lists of Lists of Bools with a strongly-typed MVC view by using Checkboxes

前端 未结 2 397
我寻月下人不归
我寻月下人不归 2021-02-04 19:39

I\'m using MVC 4, .Net 4, and Visual Studio 2012.

I\'m trying to use a fairly complex model with one of my views, and I\'m having serious trouble getting it to bind prop

相关标签:
2条回答
  • 2021-02-04 20:01

    I had to do something like this, and I had to do with the dictionary value in an array of decimals (Dictionary< string, decimal[] >). If it helps, I did like this:

    @foreach (var kvp in Model.MyDictionary)
    {
        <tr>
            <td>@kvp.Key</td>
            @for (int i = 0; i < kvp.Value.Count(); i++)
            {
                <td>
                    <input type="text" name="@("MyDictionary[" + kvp.Key + "]")" value="@kvp.Value[i]" />
                </td>
            }
        </tr>
    }
    
    0 讨论(0)
  • 2021-02-04 20:24

    Alright, I got it.

    I tried using a Tuple<int, List<List<bool>>> instead of a Dictionary<int, List<List<bool>>>. That failed, apparently because the Tuple doesn't have a 0-parameter constructor.

    Then, I tried using a custom class that had two properties, an int and a List<List<bool>>. I got that to work after some fiddling, and once that worked I was able to reverse engineer it and get the Dictionary to work.

    Here's the working version (same view model and iidToData as before):

    ...
    
    @{
        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++;
    
    }
    
    ...
    

    So, the index used on the hidden input for the dictionary key isn't the key, but is instead an enumeration of the KeyValue pairs, 0th one, 1st one, 2nd one, so on. This is the same index used to indicate the value later on.

    That leads us to another funny part. The name for the checkbox needs to have Model.DictionaryName[enumerationIndex].Value in it to indicate that we are setting the value for that indexed KeyValue pair.

    Also, the html input element produced by that helper function always has a value of true, and the second hidden input always has a value of false. The "checked" attribute indicates whether the value of the input checkbox is sent to the default binder or not, i.e. whether it gets the value of "true, false" or just "false". This is then properly interpreted by the binder as a bool value.

    Finally, the hidden input in the else block at the end adds an empty List<List<bool>> for entries that had no matching search results. The .Value pairs with the earlier .Key to indicate a full KeyValue pair to be added to the dictionary. Then, when the binder sees Model.Dictionary[index].Value[index] without ever seeing Model.Dictionary[index].Value[index][index], it makes an empty list but doesn't add any values.

    So that was unnecessarily complicated, but now hopefully others can use Dictionaries with Collection values in their ViewModels.

    0 讨论(0)
提交回复
热议问题