【问题标题】:Binding radio buttons in ASP.NET MVC page with razor使用剃刀在 ASP.NET MVC 页面中绑定单选按钮
【发布时间】:2020-08-27 16:30:03
【问题描述】:

我有一个包含 4 个单选按钮的页面(考试问题和 4 个选项可供选择)。使用下面的代码,我可以在用户单击按钮后读取选项值。

我有两个问题:

  • 为什么页面首次加载时所有单选按钮都被选中?
  • 如何找出帖子后选择了哪个单选按钮?

谢谢!

StudentQuestions.cshtml

@page "{examId:int?}"
@model VerityLearn.WebUI.Pages.Questions.StudentQuestionsModel
@{
    ViewData["Title"] = "StudentQuestions";
}
    <div>
        <form method="post">
            @Html.LabelFor(model => model.QuestionViewModel.QuestionText);

                <p>Select the correct option.</p>

                int optionIndex = -1;

                @foreach (OptionViewModel opt in Model.QuestionViewModel.Options)
                {
                    optionIndex++;

                    @Html.RadioButtonFor(model => model.QuestionViewModel.Options[optionIndex], Model.QuestionViewModel.Options[optionIndex]);
                    @opt.OptionText<br />
                }

            <button type="submit" asp-route-questionIndex="@(Model.QuestionNdx + 1)" class="btn btn-primary @nextDisabled">Next</button>

        </form>
    </div>

StudentQuestions.cshtml.cs

   public class StudentQuestionsModel : PageModel
    {
        //private readonly VerityContext _context;
        private readonly SignInManager<VerityUser> _signInManager;
        private readonly UserManager<VerityUser> _userManager;
        private readonly IStudentQuesionsUOW _studentQuesionsUOW;
        private readonly VerityLearn.DataAccess.VerityContext _context;

        public StudentQuestionsModel(
            VerityContext context,
            SignInManager<VerityUser> signInManager,
            UserManager<VerityUser> userMrg,
            IStudentQuesionsUOW studentQuesionsUOW
        )
        {
            _context = context;
            _signInManager = signInManager;
            _userManager = userMrg;
            _studentQuesionsUOW = studentQuesionsUOW;
        } // end public StudentQuestionsModel(VerityContext context, SignInManager<VerityUser> signInManager, UserManager<VerityUser> userMrg)

        [BindProperty]
        public QuestionViewModel QuestionViewModel { get; set; }

        [BindProperty]
        public Question Question { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            ... Not sure what to do here ...
        }

QuestionViewModel.cs

    public class QuestionViewModel
    {
        public int QuestionId { get; set; }

        public int ExamQuestionOrder { get; set; }

        public string QuestionText { get; set; }

        public bool? IsSingleSelection { get; set; }

        public List<OptionViewModel> Options { get; set; }
    } 

【问题讨论】:

  • 这可能会有所帮助:radiobutton in asp net mvc
  • @Ned 请同时发布OptionViewModel。学生也可以给出多个答案吗?
  • 都是非常棒的答案!太感谢了!根据客户的喜好选择一个不带JS的

标签: asp.net asp.net-mvc model-view-controller razor razor-pages


【解决方案1】:

您感兴趣的是被选中的单选按钮的值。在我的演示中,为了让事情变得更简单,我假设它是一个 id。假设单选按钮的名称为AnswerSelectedId,然后在提交表单时将标有AnswerSelectedId 的值回传到服务器。因此,您需要在模型中定义一个名为AnswerSelectedId 的属性,以便模型绑定可以匹配两者。

这里是一个快速演示,展示了您从 Mike Brind 的回答中大量借用的内容。

StudentQuestions.cshtml.cs

public class OptionViewModel
{
    public int Id { get; set; }
    public string OptionText { get; set; }
}

public class QuestionViewModel
{
    public int QuestionId { get; set; }
    public int ExamQuestionOrder { get; set; }
    public string QuestionText { get; set; }
    public bool? IsSingleSelection { get; set; }
    public List<OptionViewModel> Options { get; set; }
}

public class StudentQuestionsModelModel : PageModel
{
    public void OnGet()
    {
        QuestionViewModel = new QuestionViewModel
        {
            QuestionId = 1,
            ExamQuestionOrder = 1,
            QuestionText = "Question1",
            IsSingleSelection = false,
            Options = new List<OptionViewModel>()
            {
                new OptionViewModel
                {
                    Id = 1,
                    OptionText = "Option 1"
                },
                new OptionViewModel
                {
                    Id = 2,
                    OptionText = "Option 2"
                }
            }
        };
    }

    [BindProperty]
    public QuestionViewModel QuestionViewModel { get; set; }

    [BindProperty]
    public int AnswerSelectedId { get; set; }   //this is the key bit

    public async Task<IActionResult> OnPostAsync()
    {
        return Content($"The answer selected was {AnswerSelectedId}");
    }
}

StudentQuestions.cshtml

@page "{examId:int?}"
@model StudentQuestions.Pages.StudentQuestionsModel  

<div>
    <form method="post">
        @Html.LabelFor(model => model.QuestionViewModel.QuestionText);

        <p>Select the correct option.</p>    

        @for (var i = 0; i < Model.QuestionViewModel.Options.Count(); i++)
        {
            <input type="radio" asp-for="AnswerSelectedId" 
                   value="@Model.QuestionViewModel.Options[i].Id" /> 
                  @Model.QuestionViewModel.Options[i].OptionText
                  <br>
        }

        <button type="submit" class="btn btn-primary">Next</button>
    </form>
</div>

注意 asp-for 属性如何匹配页面模型中的属性 AnswerSelectedId。

当您提交被按下时,表单数据将被发送到服务器。如果您在发送到服务器的表单数据下使用开发人员工具,它将如下所示(取决于选择的值)

AnswerSelectedId: 1

然后模型绑定会将值绑定到名为 AnswerSelectedId 的属性,然后您就可以在 onPostAsync 方法中访问它。

【讨论】:

    【解决方案2】:

    我建议使用 Animated radios & checkboxes (noJS) ,它的动画效果非常好。您可以按照以下步骤在 Razor 页面中使用它:

    css:

    .checkbox label:after, .radio label:after {
        content: '';
        display: table;
        clear: both;
    }
    
    .checkbox .cr, .radio .cr {
        position: relative;
        display: inline-block;
        border: 1px solid #a9a9a9;
        border-radius: .25em;
        width: 1.3em;
        height: 1.3em;
        float: left;
        margin-right: .5em;
    }
    
    .radio .cr {
        border-radius: 50%;
    }
    
    .checkbox .cr .cr-icon, .radio .cr .cr-icon {
        position: absolute;
        font-size: .8em;
        line-height: 0;
        top: 50%;
        left: 20%;
    }
    
    .radio .cr .cr-icon {
        margin-left: 0.04em;
    }
    
    .checkbox label input[type="checkbox"], .radio label input[type="radio"] {
        display: none;
    }
    
    .checkbox label input[type="checkbox"] + .cr > .cr-icon, .radio label input[type="radio"] + .cr > .cr-icon {
        transform: scale(3) rotateZ(-20deg);
        opacity: 0;
        transition: all .3s ease-in;
    }
    
    .checkbox label input[type="checkbox"]:checked + .cr > .cr-icon, .radio label input[type="radio"]:checked + .cr > .cr-icon {
        transform: scale(1) rotateZ(0deg);
        opacity: 1;
    }
    
    .checkbox label input[type="checkbox"]:disabled + .cr, .radio label input[type="radio"]:disabled + .cr {
        opacity: .5;
    }
    


    控制器:

    public async Task<ActionResult> Edit(int id)
    {
        //code omitted for brevity
        return PartialView("_Edit", model);
    }
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Update([Bind(Exclude = null)] GroupViewModel model, 
        params string[] selectedRoles)
    {
        //code omitted for brevity
        await this.GroupManager.UpdateGroupAsync(group);
        selectedRoles = selectedRoles ?? new string[] { };
        await this.GroupManager.SetGroupRolesAsync(group.Id, selectedRoles);
    }
    


    查看:

    @model Demo.Models.GroupViewModel
    
    <div class="form-group">
        @Html.Label("Roles", new { @class = "col-md-3 control-label" })
        <div class="col-md-6">
    
            <div class="checkbox">
                <label>
                    <input type="checkbox" id="checkAll" name="" class="" />
                    <span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span>
                    <text id= "checkText">Tümü?</text> 
                </label>
            </div>
    
            @foreach (var role in Model.RolesList)
            {
                <div class="checkbox">
                    <label>
                        <input type="checkbox" name="selectedRoles" value="@role.Text" checked="@role.Selected" class="" />
                        <span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span>
                        @role.Text
                    </label>
                </div>
            }
        </div>
    </div>
    
    <script>
        // for selecting All / None
        $("#checkAll").change(function () {
            var checked = $(this).prop("checked");
            $("input:checkbox").prop('checked', checked);
            $('#checkText').text(checked ? 'None?' : 'All?');
        });     
    </script>
    

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      如果您想使用单选按钮来表示互斥选项,您应该通过应用相同的name 属性值将它们组合在一起:

      <input type="radio" name="question1" value="answer1" /> Answer 1
      <input type="radio" name="question1" value="answer2" /> Answer 2
      <input type="radio" name="question1" value="answer3" /> Answer 3
      

      您使用的 Html 帮助器为每个单选按钮生成不同的 id 和 name 属性值。我会避免在 Razor Pages 中使用 Html 助手来支持标签助手:

      @for (var i = 0; i <  Model.QuestionViewModel.Options.Count(); i++)
       {
          <input type="radio" asp-for="QuestionViewModel.QuestionId" value="@Model.QuestionViewModel.Options[i]" /> @Model.QuestionViewModel.Options[i].OptionText<br/>
       }
      

      更多信息:https://www.learnrazorpages.com/razor-pages/forms/radios

      【讨论】:

      • 有道理!谢谢你。你介意在 OnPostAsync() 方法中提供一个线索吗?
      • @Ned 在 OnPost 方法中,选择的值应该可以从QuestionViewModel.QuestionId访问
      • @MikeBrind 当我尝试这个时,由于 asp-for 属性,它拒绝编译。我认为一个可能的解决方法是删除模型。所以它是 asp-for="QuestionViewModel.QuestionId"
      猜你喜欢
      • 2012-06-04
      • 2022-11-28
      • 2018-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-07
      • 2013-08-05
      • 1970-01-01
      相关资源
      最近更新 更多