【问题标题】:ASP.NET MVC Binding unique radio button for list of objects in Razor @for loop, allowing only one to be selectedASP.NET MVC 绑定 Razor @for 循环中对象列表的唯一单选按钮,只允许选择一个
【发布时间】:2020-01-14 20:35:11
【问题描述】:

我有一个这样的模型:

public class ImageFileDetail {
    public HttpPostedFileBase File { get; set; }
    public bool IsMainImage { get; set; }
    public string SourceURL { get; set; }
}

我使用计数为 10 的 List<ImageFileDetail> 填充剃刀视图,允许用户上传 10 张图像。 IsMainImage 只能是一张图片。

我必须在@for 循环而不是@foreach 中执行此操作,否则模型绑定器不会绑定到列表中的每个单独对象。发布表单时,执行@foreach 会为它们提供相同的name=,因此我无法将其作为单独的对象进行迭代。

查看:

@for (var i = 0; i < Model.ImageFileDetails.Count(); i++)
{
    <tr>
        <td>
            @Html.TextBoxFor(x => x.ImageFileDetails[i].File, new { type = "file" })
        </td>
        <td>
            @Html.EditorFor(x => x.ImageFileDetails[i].SourceURL, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(x => x.ImageFileDetails[i].SourceURL, "", new { @class = "text-danger" })
        </td>
        <td>
            @*Html.EditorFor(x => x.ImageFileDetails[i].IsMainImage)*@
            // this is the radio button
            @Html.RadioButton("UniqueIsMainImage", Model.ImageFileDetails[i].IsMainImage)
            @Html.ValidationMessageFor(x => x.ImageFileDetails[i].IsMainImage, "", new { @class = "text-danger" })
        </td>
    </tr>
}

通过在@RadioButton 中为单选按钮提供相同的名称,这样我就可以只选择一个,这很好。当一个被选中时,前一个被取消选中,这是想要的结果。

问题是在POST 上,我没有得到列表中选定单选按钮的true 值,我不知道为什么。

我做错了什么?

【问题讨论】:

  • 通过将单选按钮命名为“UniqueIsMainImage”,ModelBinder 不再将其与 IsMainImage 属性相关联
  • @Kei 是的,我明白了。这是我认为我可以让单选按钮作为一组单选按钮工作的唯一方法,而不是 10 个独立的单选按钮。试图找出没有 javascript 方法的正确方法。
  • 另一种方法是在模型中而不是在每个 ImageFileDetail 中识别主图像。例如,您可以在您的模型上有一个 MainFileIndex 属性,您的单选按钮绑定到该属性。然后,单选按钮可以返回所选文件的索引。
  • @Kei 我现在实际上正在考虑这个想法,但我似乎无法让它发挥作用。 ://
  • @Kei 你是对的,我设法用@Html.RadioButtonFor(x =&gt; Model.SelectedImageId, Model.ImageFileDetails[i].Id) 得到它。然后在我的控制器中,我可以将bool 设置为true 以获得正确的Id。谢谢!

标签: asp.net-mvc for-loop razor model-binding


【解决方案1】:

我必须将单选按钮更改为 @Html.RadioButtonFor(x =&gt; Model.SelectedImageId, Model.ImageFileDetails[i].Id) 并为列表中的每个对象传递一个 Id

视图模型:

public class ViewModel
{
    public List<ImageFileDetail> ImageFileDetails { get; set; } = new List<ImageFileDetail>();
    public int? SelectedImageId { get; set; }
}

public class ImageFileDetail {
    public int Id { get; set; } // for main image radio button
    public HttpPostedFileBase File { get; set; }
    public bool IsMainImage { get; set; }
    public string SourceURL { get; set; }
}

查看:

@for (var i = 0; i < Model.ImageFileDetails.Count(); i++)
{
    <tr>
        <td>
            @Html.TextBoxFor(x => x.ImageFileDetails[i].File, new { type = "file" })
        </td>
        <td>
            @Html.EditorFor(x => x.ImageFileDetails[i].SourceURL, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(x => x.ImageFileDetails[i].SourceURL, "", new { @class = "text-danger" })
        </td>
        <td>
            @*Html.EditorFor(x => x.ImageFileDetails[i].IsMainImage)*@
            @Html.RadioButtonFor(x => Model.SelectedImageId, Model.ImageFileDetails[i].Id)
            @Html.ValidationMessageFor(x => x.ImageFileDetails[i].IsMainImage, "", new { @class = "text-danger" })
        </td>
    </tr>
}

然后在我的控制器中,当迭代发布的列表时,我将SelectedImageIdIsMainImage 设置为true。

后控制器:

foreach (var fileDetail in viewModel.ImageFileDetails)
{       
        if (fileDetail.Id == viewModel.SelectedImageId)
            fileDetail.IsMainImage = true;      
}

感谢大家对我的信任。

【讨论】:

    【解决方案2】:

    这可能并不完全是您要寻找的,而是与您的 for/foreach 语句相关的内容 - 如果您允许,razor 实际上会为您执行此操作:

    我认为你也应该使用 RadioButtonFor。

    您可以利用剃刀视图中的模板,让它为您处理列表/数组。所以而不是:

    @Html.EditorFor(x => x.ImageFileDetails[i].SourceURL,...
    

    你应该这样做(注意模板文件的名称应该与类型名称匹配):

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

    然后创建一个EditorTemplates/ImageFileDetail.cshtml模板:

    @model <namespace>.ImageFileDetail
    
     <tr>
        <td>
            @Html.TextBoxFor(x => x.File, new { type = "file" })
        </td>
        <td>
            @Html.EditorFor(x => x.SourceURL, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(x => x.SourceURL, "", new { @class = "text-danger" })
        </td>
        <td>
            @*Html.EditorFor(x => x.IsMainImage)*@
            // this is the radio button
            @Html.RadioButtonFor(x => x.IsMainImage, x.IsMainImage, new { name = "UniqueIsMainImage" })
    
            @Html.ValidationMessageFor(x => x.IsMainImage, "", new { @class = "text-danger" })
        </td>
    </tr>
    

    【讨论】:

    • 我收到No overload for method 'RadioButtonFor' takes 1 arguments
    • @justiceorjustus 我刚刚更新了 radiobuttonfor 上的第二个参数用于选定的值。不过,根据我最初的声明 - 这可能不完全是你所需要的 - 它更多地参考了 for/foreach 语句
    • 现在每个单选按钮都被打勾了,因为它们与id's(例如ImageFileDetails_0__IsMainImageImageFileDetails_1__IsMainImage等)作为独立组。但是,我确实证明了其中的逻辑我的答案 + 使用 EditorTemplate 将是最合适的解决方案,imo。
    • @justiceorjustus 刚刚再次更新为您是原来的 RadioButton - 就像我说的那样 - 我不希望这是答案 - 这只是一个提示,还有另一种处理列表的方法/ razor 中的数组
    • @justiceorjustus 你可以通过 HtmlAttributes 设置名称吗? ID 不同并不重要 - name 属性用于分组和发送到服务器。
    猜你喜欢
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-04
    • 2010-11-02
    • 2016-07-07
    • 1970-01-01
    • 2017-09-05
    相关资源
    最近更新 更多