我想根据 asp.net MVC 中 Html.TextBoxFor 的条件设置禁用属性,如下所示
@Html.TextBoxFor(model => model.ExpireDate, new { style = "width: 70px;", maxlength = "10", id = "expire-date" disabled = (Model.ExpireDate == null ? "disable" : "") })
这个助手有两个输出:disabled=“disabled”或disabled=“”。两个主题都会禁用文本框。
如果 Model.ExpireDate == null,我想禁用文本框,否则我想启用它
有效的方法是:
disabled="disabled"
浏览器也可能接受
disabled=""
,但我会推荐您第一种方法。
话虽这么说,我建议您编写一个自定义 HTML 帮助程序,以便将这个禁用功能封装到可重用的代码中:
using System;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes,
bool disabled
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
if (disabled)
{
attributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(expression, attributes);
}
}
你可以像这样使用:
@Html.MyTextBoxFor(
model => model.ExpireDate,
new {
style = "width: 70px;",
maxlength = "10",
id = "expire-date"
},
Model.ExpireDate == null
)
您可以为这个助手带来更多智能:
public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
if (metaData.Model == null)
{
attributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(expression, attributes);
}
}
现在您不再需要指定禁用条件:
@Html.MyTextBoxFor(
model => model.ExpireDate,
new {
style = "width: 70px;",
maxlength = "10",
id = "expire-date"
}
)
实际上,内部行为是将匿名对象转换为字典。 所以在这些情况下我要做的就是找一本字典:
@{
var htmlAttributes = new Dictionary<string, object>
{
{ "class" , "form-control"},
{ "placeholder", "Why?" }
};
if (Model.IsDisabled)
{
htmlAttributes.Add("disabled", "disabled");
}
}
@Html.EditorFor(m => m.Description, new { htmlAttributes = htmlAttributes })
或者,正如斯蒂芬评论的这里:
@Html.EditorFor(m => m.Description,
Model.IsDisabled ? (object)new { disabled = "disabled" } : (object)new { })
我喜欢达林方法。但解决这个问题的快速方法,
Html.TextBox("Expiry", null, new { style = "width: 70px;", maxlength = "10", id = "expire-date", disabled = "disabled" }).ToString().Replace("disabled=\"disabled\"", (1 == 2 ? "" : "disabled=\"disabled\""))
我使用的一种简单方法是条件渲染:
@(Model.ExpireDate == null ?
@Html.TextBoxFor(m => m.ExpireDate, new { @disabled = "disabled" }) :
@Html.TextBoxFor(m => m.ExpireDate)
)
如果你不使用 html 助手,你可以使用简单的三元表达式,如下所示:
<input name="Field"
value="@Model.Field" tabindex="0"
@(Model.IsDisabledField ? "disabled=\"disabled\"" : "")>
我使用一些扩展方法实现了它
private const string endFieldPattern = "^(.*?)>";
public static MvcHtmlString IsDisabled(this MvcHtmlString htmlString, bool disabled)
{
string rawString = htmlString.ToString();
if (disabled)
{
rawString = Regex.Replace(rawString, endFieldPattern, "$1 disabled=\"disabled\">");
}
return new MvcHtmlString(rawString);
}
public static MvcHtmlString IsReadonly(this MvcHtmlString htmlString, bool @readonly)
{
string rawString = htmlString.ToString();
if (@readonly)
{
rawString = Regex.Replace(rawString, endFieldPattern, "$1 readonly=\"readonly\">");
}
return new MvcHtmlString(rawString);
}
然后....
@Html.TextBoxFor(model => model.Name, new { @class= "someclass"}).IsDisabled(Model.ExpireDate == null)
使用 RouteValueDictionary(作为 htmlAttributes 工作正常,因为它基于 IDictionary)和扩展方法解决了这个问题:
public static RouteValueDictionary AddIf(this RouteValueDictionary dict, bool condition, string name, object value)
{
if (condition) dict.Add(name, value);
return dict;
}
用途:
@Html.TextBoxFor(m => m.GovId, new RouteValueDictionary(new { @class = "form-control" })
.AddIf(Model.IsEntityFieldsLocked, "disabled", "disabled"))
这已经晚了,但可能对某些人有帮助。
我扩展了@DarinDimitrov的答案,以允许传递第二个对象,该对象采用任意数量的布尔html属性,如
disabled="disabled" checked="checked", selected="selected"
等。
仅当属性值为 true 时才会渲染该属性,其他任何值都不会渲染该属性。
自定义可重用 HtmlHelper:
public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes,
object booleanHtmlAttributes)
{
var attributes = new RouteValueDictionary(htmlAttributes);
//Reflect over the properties of the newly added booleanHtmlAttributes object
foreach (var prop in booleanHtmlAttributes.GetType().GetProperties())
{
//Find only the properties that are true and inject into the main attributes.
//and discard the rest.
if (ValueIsTrue(prop.GetValue(booleanHtmlAttributes, null)))
{
attributes[prop.Name] = prop.Name;
}
}
return htmlHelper.TextBoxFor(expression, attributes);
}
private static bool ValueIsTrue(object obj)
{
bool res = false;
try
{
res = Convert.ToBoolean(obj);
}
catch (FormatException)
{
res = false;
}
catch(InvalidCastException)
{
res = false;
}
return res;
}
}
你可以像这样使用:
@Html.MyTextBoxFor(m => Model.Employee.Name
, new { @class = "x-large" , placeholder = "Type something…" }
, new { disabled = true})
如果您不想使用 Html Helpers 看看我的解决方案
disabled="@(your Expression that returns true or false")"
它
@{
bool isManager = (Session["User"] as User).IsManager;
}
<textarea rows="4" name="LetterManagerNotes" disabled="@(!isManager)"></textarea>
我认为更好的方法是在控制器中进行检查并将其保存在视图(Razor 引擎)内可访问的变量中,以便使
the view free from business logic
另一种解决方案是在调用
Dictionary<string, object>
之前创建一个 TextBoxFor
并传递该字典。在字典中,仅当要禁用文本框时才添加 "disabled"
键。不是最巧妙的解决方案,但简单明了。
另一种方法是禁用客户端的文本框。
在您的情况下,您只有一个需要禁用的文本框,但请考虑您有多个需要禁用的输入、选择和文本区域字段的情况。
通过 jquery + 来做到这一点要容易得多(因为我们不能依赖来自客户端的数据)向控制器添加一些逻辑以防止保存这些字段。
这是一个例子:
<input id="document_Status" name="document.Status" type="hidden" value="2" />
$(document).ready(function () {
disableAll();
}
function disableAll() {
var status = $('#document_Status').val();
if (status != 0) {
$("input").attr('disabled', true);
$("textarea").attr('disabled', true);
$("select").attr('disabled', true);
}
}
我喜欢扩展方法,这样你就不必传递所有可能的参数。
然而,使用正则表达式可能非常棘手(而且速度有些慢),所以我使用
XDocument
来代替:
public static MvcHtmlString SetDisabled(this MvcHtmlString html, bool isDisabled)
{
var xDocument = XDocument.Parse(html.ToHtmlString());
if (!(xDocument.FirstNode is XElement element))
{
return html;
}
element.SetAttributeValue("disabled", isDisabled ? "disabled" : null);
return MvcHtmlString.Create(element.ToString());
}
使用这样的扩展方法:
@Html.EditorFor(m => m.MyProperty).SetDisabled(Model.ExpireDate == null)
这个扩展非常简单。
using System.Web.Mvc.Html;
using System.Web.Mvc;
namespace MyApplication.Extensions
{
public static class MyExtensions
{
public static MvcHtmlString Locked(this MvcHtmlString htmlString, bool isAdmin)
{
string html = htmlString.ToString();
return new MvcHtmlString(isAdmin ? html : html.Replace("id=", " disabled id="));
}
}
}
然后,您可以根据视图顶部设置的变量设置可以编辑哪些字段。
示例:
@using MyApplication.Extensions
@model MyModel
@{
bool isAdmin = (User.IsInRole("Admin") || User.IsInRole("Manager"));
}
.
.
<div class="col-md-6">
@Html.TextBoxFor(m => m.CommisionAmt).Locked(isAdmin)
</div>