我刚开始学习ASP.NET MVC。我将如何创建可重用的三态checbox?在WebForms中,这将是一个控件,但我不知道MVC等价物。
答案 0 :(得分:6)
向TriStateCheckBox
添加TriStateCheckBoxFor
(如果使用强类型重载,则为HtmlHelper
)扩展方法,并将该扩展方法类的命名空间添加到namespaces
部分你的web.config。
至于实施,我建议您查看the InputExtensions source on codeplex并使用它来创建自己的。
答案 1 :(得分:1)
ASP.NET MVC当然不提供这样的组件,实际上它只依赖于HTML中可用的标准元素,但您可能想要查看此solution。
答案 2 :(得分:1)
查看渲染 - 呈现HTML内容时,您无法在
<input type="checkbox" />
上放置属性indeterminate
。
在某些时候,您必须使用JavaScript 来抓取元素并set the indeterminate property:
// vanilla js
document.getElementById("myChk").indeterminate = true;
// jQuery
$("#myCheck).prop("indeterminate", true);
表单数据 - 模型绑定将始终限制为请求中实际发送的值,来自url或数据有效负载(在POST上)。
在这个简化的示例中,未经检查和不确定的复选框都被视为相同:
您可以在 Stack Snippet :
中自行确认
label {
display: block;
margin-bottom: 3px;
}
&#13;
<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>
&#13;
模型绑定 - 此外,模型绑定仅发生在实际发送的属性上。即使对于常规复选框,这实际上也会产生问题,因为它们在未选中时不会发布值。值类型始终具有默认值,但是,如果它是模型中唯一的属性,则MVC如果没有看到任何属性,则不会对整个类进行新建。
ASP.NET通过为每个复选框发出两个输入来解决此问题:
注意:隐藏的输入可以保证&#39; false&#39;即使复选框不是checked
,也会发送值。当选中复选框 时,允许HTTP提交多个具有相同名称的值,但ASP.NET MVC将只接受第一个实例,因此它将像我们一样返回true
&#39 ; d期待。
我们可以渲染checkbox for a nullable boolean,但这实际上只能通过在渲染时转换null
→false
来保证bool。在服务器和客户端之间共享不确定状态仍然很困难。如果您不需要回复不确定,这可能是最干净/最简单的实施。
由于使用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 System.Windows.Forms.CheckState, but duplicated to remove dependency on Forms.dll</remarks>
public enum CheckState
{
Checked,
Indeterminate,
Unchecked
}
然后将以下属性添加到Model 而不是布尔值:
public CheckState OpenTasks { get; set; }
然后为该属性创建一个 EditorTemplate ,该属性将呈现我们想要在隐藏输入 PLUS 内部保留的实际属性我们将使用的复选框控件更新该属性
Views/Shared/EditorTemplates/CheckState.cshtml
:
@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