【问题标题】:ASP.NET MVC: Tri-state checkboxASP.NET MVC:三态复选框
【发布时间】:2011-05-16 01:03:55
【问题描述】:

我刚刚开始学习 ASP.NET MVC。我将如何创建一个可重复使用的三态复选框?在 WebForms 中,这将是一个控件,但我不知道 MVC 等效项。

【问题讨论】:

    标签: asp.net-mvc


    【解决方案1】:

    TriStateCheckBox(或TriStateCheckBoxFor,如果您使用强类型重载)扩展方法添加到HtmlHelper,并将该扩展方法类的命名空间添加到您的web.config 的namespaces 部分。

    至于实现,我建议查看 the InputExtensions source on codeplex 并使用它来创建自己的。

    【讨论】:

    • 顺便说一句,如果他们将 TriStateCheckBox 添加到 asp.net mvc 或 MvcContrib 的下一个版本中,那就太好了。
    • @Denis - 由于三态复选框不是标准的 HTML 控件,它们不太可能被正式添加。
    【解决方案2】:

    限制:

    查看渲染 - 渲染 HTML 内容时,您不能在 <input type="checkbox" /> 上放置任何属性来赋予其属性 indeterminate

    在某些时候,您将必须使用 JavaScript 来获取元素和set the indeterminate property

    // vanilla js
    document.getElementById("myChk").indeterminate = true;
    // jQuery
    $("#myCheck).prop("indeterminate", true);
    

    表单数据 - 模型绑定将始终限于请求中实际发送的值,无论是从 url 还是数据负载(在 POST 上)。

    在这个简化的示例中,未选中和不确定的复选框的处理方式相同:

    您可以在此堆栈片段中亲自确认:

    label {
      display: block;
      margin-bottom: 3px;
    }
    <form action="#" method="post">
    
      <label >
        <input type="checkbox" name="chkEmpty">  
        Checkbox
      </label>
      <label >
        <input type="checkbox" name="chkChecked" checked>  
        Checkbox with Checked 
      </label>
      <label >
        <input type="checkbox" name="chkIndeterminate" id="chkIndeterminate">  
        <script> document.getElementById("chkIndeterminate").indeterminate = true; </script>
        Checkbox with Indeterminate 
      </label>
    
      <label >
        <input name="RegularBool" type="checkbox" value="true">
        <input name="RegularBool" type="hidden" value="false">
        RegularBool
      </label>
    
     
    
    
      <input type="submit" value="submit"/>
      
    </form>

    模型绑定 - 此外,模型绑定只会发生在实际发送的属性上。即使对于常规复选框,这实际上也会带来问题,因为它们在未选中时不会发布值。值类型总是有一个默认值,但是,如果这是你模型中唯一的属性,如果 MVC 没有看到任何属性,它就不会新建整个类。

    ASP.NET 通过为每个复选框发出两个输入来解决这个问题:

    注意:隐藏的输入保证即使复选框不是checked 也会发送“假”值。当复选框被选中时,HTTP 被允许提交多个同名的值,但是 ASP.NET MVC 将只接受第一个实例,所以它会像我们期望的那样返回true


    仅渲染解决方案

    我们可以渲染一个checkbox for a nullable boolean,但这实际上只能通过在渲染时转换nullfalse来保证一个布尔值。在服务器和客户端之间共享不确定的状态仍然很困难。如果您不需要不确定地回发,这可能是最干净/最简单的实现。


    往返解决方案

    由于使用 HTML 复选框来捕获和发布所有 3 个可见状态存在严重限制,因此让我们将控件(复选框)的视图与我们想要保留的三态值分开,然后保持它们同步通过 JavsScript。由于无论如何我们已经需要 JS,这并没有真正增加我们的依赖链。

    从一个包含我们值的枚举开始:

    /// <summary> Specifies the state of a control, such as a check box, that can be checked, unchecked, or set to an indeterminate state.</summary>
    /// <remarks> Adapted from @987654325@, but duplicated to remove dependency on Forms.dll</remarks>
    public enum CheckState
    {
        Checked,
        Indeterminate,
        Unchecked
    }

    然后将以下属性添加到您的模型中而不是布尔值:

    public CheckState OpenTasks { get; set; }
    

    然后为属性创建一个 EditorTemplate,该属性将呈现我们想要在隐藏输入中持久化的实际属性PLUS一个复选框控件,我们将使用它来更新那个属性

    Views/Shared/EditorTemplates/<b>CheckState.cshtml</b>:

    @model CheckState
    
    @Html.HiddenFor(model => model, new { @class = "tri-state-hidden" })
    @Html.CheckBox(name: "",
                   isChecked: (Model == CheckState.Checked),
                   htmlAttributes: new { @class = "tri-state-box" })
    

    注意:我们使用与 ASP.NET MVC 相同的 hack 来提交两个具有相同名称的字段,并首先放置我们想要保留的 HiddenFor 值,以便它获胜。这只是为了方便遍历 DOM 并找到相应的值,但您可以使用不同的名称来防止任何可能的重叠。

    然后,在您看来,您可以使用编辑器模板渲染属性和复选框,就像使用复选框一样,因为它同时渲染两者。因此,只需将其添加到您的视图中:

    @Html.EditorFor(model => model.OpenTasks)
    

    最后一点是在加载时通​​过 JavaScript 保持它们同步,并且每当复选框更改如下:

    // on load, set indeterminate
    $(".tri-state-hidden").each(function() {
        var isIndeterminate = this.value === "@CheckState.Indeterminate";
        if (isIndeterminate) {
            var $box = $(".tri-state-box[name='" + this.name + "'][type='checkbox']");
            $box.prop("indeterminate", true);
        }
    });
    
    // on change, keep synchronized
    $(".tri-state-box").change(function () {
        var newValue = this.indeterminate ? "@CheckState.Indeterminate"
                     : this.checked ? "@CheckState.Checked"
                                    : "@CheckState.Unchecked";
    
        var $hidden = $(".tri-state-hidden[name='" + this.name + "'][type='hidden']");
        $hidden.val(newValue);
    });
    

    然后,您可以在您的商业模式中随意使用。例如,如果您想映射到一个可为空的布尔值,您可以使用 CheckState 属性作为支持值,并通过 bool? 中的 getter/setter 公开/修改,如下所示:

    public bool? OpenTasksBool
    {
        get
        {
            if (OpenTasks == CheckState.Indeterminate) return null;
            return OpenTasks == CheckState.Checked;
        }
        set
        {
            switch (value)
            {
                case null: OpenTasks = CheckState.Indeterminate; break;
                case true: OpenTasks = CheckState.Checked; break;
                case false: OpenTasks = CheckState.Unchecked; break;
            }
        } 
    }
    

    替代解决方案

    另外,根据您的域模型,您可以只使用Yes, No, ⁿ/ₐ radio buttons

    【讨论】:

      【解决方案3】:

      ASP.NET MVC 当然不提供这样的组件,实际上它只是依赖于 HTML 中可用的标准元素,但你可能想看看这个solution

      【讨论】:

      • 您可以添加新的 HTML 助手,这与 Web 控件的原理类似。
      • 我没想到,我正试图寻求帮助来创建我自己的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 2011-08-03
      • 1970-01-01
      • 2016-10-26
      • 2011-03-07
      • 2019-02-14
      • 2013-08-05
      相关资源
      最近更新 更多