将mvc3 radiobutton绑定到模型的正确方法

Div*_*Dan 48 asp.net-mvc-3

我有一个视图,其中包含我的网站条款和条件的单选按钮列表.

例如

Yes
@Html.RadioButtonFor(model => model.TermsAndConditions, "True")
No
@Html.RadioButtonFor(model => model.TermsAndConditions, "False",
     new { Checked = "checked" })
</div>
@Html.ValidationStyledMessageFor(model => model.TermsAndConditions)
Run Code Online (Sandbox Code Playgroud)

如果用户完成表单没有任何错误,一切正常,但如果我进行服务器端验证并刷新页面,则会丢失用户为单选按钮做出的选择,并且选定的无线电将返回到默认的假字段.

我是如何绑定radiobutton所以如果用户选择为true,即使在服务器端验证之后,该值仍然保持不变?

任何建议都会很棒!

Gla*_*zed 95

简而言之,您需要做三件事:

  1. new { Checked = "checked" }从第二个单选按钮中删除.这个硬编码的检查值将覆盖所有魔法.
  2. 从控制器操作返回ViewResult时,请为其提供一个ModelAndConditions为false的模型类实例.这将提供您需要的默认false值,以便为您预先选择false单选按钮.
  3. 使用truefalse作为单选按钮的值而不是"True""False".这是因为您的属性属于类型bool.严格地说,你恰巧为true和选择了正确的字符串表示false,但是RadioButtonFor方法的value参数是类型object.最好传递您想要比较的实际类型,而不是自己将其转换为字符串.更多关于此的信息.

以下是深入的内容:

该框架希望自动为您完成所有这些操作,但是您错误地执行了前两项操作,这使您必须与框架作斗争才能获得所需的行为.

RadioButtonFor方法调用.ToString()您指定的属性的值,并将其与.ToString()创建单选按钮时传入的值进行比较.如果它们相等,那么它在内部设置isChecked = true并最终checked="checked"在HTML中呈现.这就是它决定检查哪个单选按钮的方法.它只是将单选按钮的值与属性的值进行比较,并检查匹配的值.

您可以通过这种方式为几乎任何属性渲染单选按钮,它将神奇地工作.字符串,整数,甚至枚举类型都有效!任何具有ToString返回唯一表示对象值的字符串的方法的对象都可以使用.您只需确保将单选按钮的值设置为您的属性可能实际具有的值.最简单的方法是传递值本身,而不是值的字符串表示.让框架为您将其转换为字符串.

(既然你发生在正确字符串表示通过truefalse,然后将这些值将只要您修复两个实际工作的失误,但它仍然是明智的实际值,而不是他们的字符串传递.)

你的第一个真正的错误是硬编码Checked = "checked""No"单选按钮.这将覆盖框架尝试为您执行的操作,并导致始终检查此单选按钮.

显然,您希望预先选择"否"单选按钮,但您必须以与上述所有内容兼容的方式执行此操作.您需要为视图提供模型类的实例,其中TermsAndConditions设置为false,并让它"绑定"到单选按钮.通常,响应URL的初始GET请求的控制器操作根本不会向View提供模型类的实例.通常,你只是return View();.但是,由于您希望选择默认值,因此必须为视图提供将TermsAndConditions设置为false的模型实例.

以下是一些说明所有这些的源代码:

您可能已经拥有的某种Account类.(你的View的型号):

public class Account
{
    public bool TermsAndConditions { get; set; }
    //other properties here.
}
Run Code Online (Sandbox Code Playgroud)

控制器中的一些方法:

//This handles the initial GET request.
public ActionResult CreateAccount()
{
    //this default instance will be used to pre-populate the form, making the "No" radio button checked.
    var account = new Account
    {
        TermsAndConditions = false
    };

    return View( account );
}

//This handles the POST request.
[HttpPost]
public ActionResult CreateAccount( Account account )
{
    if ( account.TermsAndConditions )
    {
        //TODO: Other validation, and create the account.
        return RedirectToAction( "Welcome" );
    }
    else
    {
        ModelState.AddModelError( "TermsAndConditionsAgreement", "You must agree to the Terms and Conditions." );
        return View( account );
    }           
}

//Something to redirect to.
public ActionResult Welcome()
{
    return View();
}
Run Code Online (Sandbox Code Playgroud)

整个视图:

@model Account
@{
    ViewBag.Title = "Create Account";
}
@using ( Html.BeginForm() )
{
    <div>
        <span>Do you agree to the Terms and Conditions?</span>
        <br />
        @Html.RadioButtonFor( model => model.TermsAndConditions, true, new { id = "TermsAndConditions_true" } )
        <label for="TermsAndConditions_true">Yes</label>
        <br />
        @Html.RadioButtonFor( model => model.TermsAndConditions, false, new { id = "TermsAndConditions_false" } )
        <label for="TermsAndConditions_false">No</label>
        <br />
        @Html.ValidationMessage( "TermsAndConditionsAgreement" )
    </div>
    <div>
        <input id="CreateAccount" type="submit" name="submit" value="Create Account" />
    </div>
}
Run Code Online (Sandbox Code Playgroud)

奖励:您会注意到我在单选按钮上添加了一些额外的功能.我使用的HTML label元素的for属性设置为每个单选按钮的ID,而不是仅使用纯文本作为单选按钮标签.这使用户可以单击标签来选择单选按钮,而不必单击单选按钮本身.这是标准的HTML.为了实现这一点,我必须在单选按钮上设置手动ID,否则它们都将获得相同的ID"仅限条款和条件",这是行不通的.

  • 您也可以将radiobutton包装在<label>中.http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1 (3认同)

小智 15

您需要在此处执行一些操作,以确保在服务器端验证后维护用户的选择.

a)将每个无线电的"已检查"属性绑定到视图中的模型,例如:

Yes
@Html.RadioButtonFor(model => model.TermsAndConditions, "True", model.TermsAndConditions == true ? new { Checked = "checked" } : null)
No
@Html.RadioButtonFor(model => model.TermsAndConditions, "False", model.TermsAndConditions == false ? new { Checked = "checked" } : null)
Run Code Online (Sandbox Code Playgroud)

b)要在首次显示视图时定义初始默认值,请在GET请求中(在控制器操作中)初始化返回到视图的模型,例如:

public ActionResult SomeForm()
{
    return View(new SomeModel { TermsAndConditions = false });
}
Run Code Online (Sandbox Code Playgroud)

b)确保在[HttpPost]控制器操作中,在验证失败时返回模型,例如:

[HttpPost]
public ActionResult SomeForm(SomeModel model)
{
    if (!ModelState.IsValid)
        return View(model);

    // Do other stuff here
}
Run Code Online (Sandbox Code Playgroud)

这种方式在验证失败后在响应中呈现视图时,它将具有传入的实际模型状态(从而保持用户的选择).