【问题标题】:Bind multiple radiobuttons to individual booleans将多个单选按钮绑定到单个布尔值
【发布时间】:2023-03-18 20:35:02
【问题描述】:

背景

我有一个包含三个布尔值的模型

public class PageDataModel
{
    public bool setting1 { get; set; }
    public bool setting2 { get; set; }
    public bool setting3 { get; set; }
}

如果一个值为真,则其他值必须为假。

在我看来,我正在显示三个单选按钮:

我认为的 Razor 代码:

<div class="row">
        <div class="radio">
            @if (Model.Setting1)
            {
                @Html.RadioButtonFor(m => m.Setting1,  "Setting1", new { Checked = "checked", Name = "Group"})
            }
            else
            {
                @Html.RadioButtonFor(m => m.Setting1, "Setting1", new { Name = "Group"})
            }

            @Html.Label("Setting1")
        </div>
        <div class="radio">
            @if (Model.Setting2)
            {
                @Html.RadioButtonFor(m => m.Setting2, "Setting2", new { Checked = "checked", Name = "Group" })
            }
            else
            {
                @Html.RadioButtonFor(m => m.Setting2, "Setting2", new { Name = "Group"})
            }
            @Html.Label("Setting2")
        </div>
        <div class="radio">
            @if (Model.Setting3)
            {
                @Html.RadioButtonFor(m => m.Setting3, "Setting3", new { Checked = "checked", Name = "Group" })
            }
            else
            {
                @Html.RadioButtonFor(m => m.Setting3, "Setting3", new { Name = "Group"})
            }
            @Html.Label("Setting3")
        </div>
        <button type="submit" class="btn btn-default">Save</button>
    </div>

在我的控制器中,我返回了一个设置 1 设置为 true 的模型:

var model = new PageDataModel
        {
            Setting1 = true,
            Setting2 = false,
            Setting3 = false
        };
        return View(model);

这可以正常工作,页面加载时选中了“设置 1”单选按钮。

问题

当我提交表单时,发布的模型包含所有错误值,无论选中哪个单选按钮。

我尝试将值从“setting1”更改为真/假,但这对返回的数据没有影响。

我很确定我没有正确设置绑定,但我不确定我哪里出错了。

我发现的所有其他示例都是将两个单选按钮绑定到一个布尔值(例如,一对是/否单选按钮绑定到一个布尔值)。我可以更改代码以使用一个 int 属性,但我想使用 bools 来解决这个问题。

我做错了什么?我在这里误用了单选按钮吗?

【问题讨论】:

  • 一个属性只有一个单选按钮是没有意义的。您需要为每个属性设置 2 个单选按钮,一个带有 value="true" 和一个带有 value="false" (并删除所有 if 块) - @Html.RadioButtonFor(m =&gt; m.Setting1, true) @Html.RadioButtonFor(m =&gt; m.Setting1, false)
  • 我很确定我在这里使用了错误的控件,只是想看看是否可以通过这种方式解决它。单选按钮是否被选中(真/假),当时对我来说是有意义的。如果块有点混乱,但这仍然处于 PoC 阶段。一旦我得到它的工作,我会整理它们。
  • 所有属性为假的原因是您的单选按钮有value="Setting1"value="Setting2" 等不能绑定到bool,因此这些值是它们的默认值(false
  • 这是有道理的。如果选中,有没有办法将值绑定到?
  • RadioButtonFor() 方法会自动执行此操作。根据我之前的cmets中的代码,如果值为true,将检查第一个按钮,否则将检查第二个。

标签: c# asp.net-mvc razor


【解决方案1】:

从技术上讲,只要您将值设置为true,它就可以正常工作。例如:

@Html.RadioButtonFor(m => m.setting1, true)

这样,如果选择了电台,它将发布true

然而,这里不可克服的问题是,这不是无线电的设计方式。无线电是组的一部分,由name 属性的值确定。这会导致选择一个无线电取消选择具有相同name 属性的所有无线电。但是,使用RadioButtonFor 将根据属性名称为每个无线电赋予不同的名称。换句话说,你最终会得到:

<input type="radio" id="setting1" name="setting1" value="true" />
<input type="radio" id="setting2" name="setting2" value="true" />
<input type="radio" id="setting3" name="setting3" value="true" />

然后,每个收音机将属于不同组的一部分,每个组仅包含一个收音机(这意味着默认情况下会选择每个收音机)。您可以覆盖 name 属性,但发布的值将不再绑定到实际属性。例如,如果您有:

<input type="radio" id="setting1" name="setting" value="true" />
<input type="radio" id="setting2" name="setting" value="true" />
<input type="radio" id="setting3" name="setting" value="true" />

如果他们现在都属于同一个广播组,则该值将发布到 setting,并且它始终为真。

总之,没有办法让这个工作像这样。您可以做的是使用另一个属性代理该值。

public class PageDataModel
{
    public bool setting1 { get; set; }
    public bool setting2 { get; set; }
    public bool setting3 { get; set; }

    public string SelectedSetting
    {
        get
        {
            if (setting1) return "setting1";
            if (setting2) return "setting2";
            if (setting3) return "setting3";
            return null; // or you can set a default here
        }
        set
        {
            switch (value)
            {
                case "setting1":
                    setting1 = true;
                    break;
                case "setting2":
                    setting2 = true;
                    break;
                case "setting3":
                    setting3 = true;
                    break;
            }
        }
    }
}

那么,在你看来:

<div class="radio">
    <label>
        @Html.RadioButtonFor(m => m.SelectedSetting, "setting1")
        @Html.DisplayNameFor(m => m.setting1)
    </label>
</div>
<div class="radio">
    <label>
        @Html.RadioButtonFor(m => m.SelectedSetting, "setting2")
        @Html.DisplayNameFor(m => m.setting2)
    </label>
</div>
<div class="radio">
    <label>
        @Html.RadioButtonFor(m => m.SelectedSetting, "setting3")
        @Html.DisplayNameFor(m => m.setting3)
    </label>
</div>

现在,收音机将全部归类为“SelectedSetting”,并将发布到SelectedSetting 属性。该属性上的自定义 getter 和 setter 可确保在实际 settingX 属性上设置正确的布尔值。

【讨论】:

  • 太棒了。我决定重构我的代码以使用一个 int 值(实现起来更容易/更干净),但这回答了最初的问题。谢谢!
  • 可能是个好主意。我想展示它是如何完成的,但是将属性名称硬编码为字符串使其成为一个非常脆弱的解决方案。
  • 使用nameof 会使它不那么脆弱。 case "setting1": -> case nameof(PageDataModel.setting1 ):
猜你喜欢
  • 2015-04-27
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
  • 2013-06-02
  • 2021-12-24
  • 1970-01-01
相关资源
最近更新 更多