根据Html.TextBoxFor的条件设置禁用属性

时间:2011-07-12 06:08:49

标签: asp.net-mvc asp.net-mvc-3 razor html-helper

我想根据下面的asp.net MVC中的Html.TextBoxFor的条件设置disable属性

@Html.TextBoxFor(model => model.ExpireDate, new { style = "width: 70px;", maxlength = "10", id = "expire-date" disabled = (Model.ExpireDate == null ? "disable" : "") })

此助手有两个输出禁用=“禁用”或禁用=“”。两个主题都使文本框无效。

如果Model.ExpireDate == null我要禁用文本框,否则我想启用它

12 个答案:

答案 0 :(得分:79)

有效的方法是:

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" 
    }
)

答案 1 :(得分:39)

实际上,内部行为是将匿名对象转换为字典。 所以我在这些场景中所做的就是去找字典:

@{
  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 })

或者,斯蒂芬评论here

@Html.EditorFor(m => m.Description,
    Model.IsDisabled ? (object)new { disabled = "disabled" } : (object)new { })

答案 2 :(得分:22)

我喜欢Darin方法。但是快速解决这个问题的方法,

Html.TextBox("Expiry", null, new { style = "width: 70px;", maxlength = "10", id = "expire-date", disabled = "disabled" }).ToString().Replace("disabled=\"disabled\"", (1 == 2 ? "" : "disabled=\"disabled\""))

答案 3 :(得分:13)

我使用一些扩展方法实现了它

public static MvcHtmlString IsDisabled(this MvcHtmlString htmlString, bool disabled)
{
    string rawstring = htmlString.ToString();
    if (disabled)
    {
        rawstring = rawstring.Insert(rawstring.Length - 2, "disabled=\"disabled\"");
    }
    return new MvcHtmlString(rawstring);
}

public static MvcHtmlString IsReadonly(this MvcHtmlString htmlString, bool @readonly)
{
    string rawstring = htmlString.ToString();
    if (@readonly)
    {
        rawstring = rawstring.Insert(rawstring.Length - 2, "readonly=\"readonly\"");
    }
    return new MvcHtmlString(rawstring);
}

然后......

@Html.TextBoxFor(model => model.Name, new { @class= "someclass"}).IsDisabled(Model.ExpireDate == null)

答案 4 :(得分:10)

如果您不使用html助手,您可以使用简单的三元表达式:

<input name="Field"
       value="@Model.Field" tabindex="0"
       @(Model.IsDisabledField ? "disabled=\"disabled\"" : "")>

答案 5 :(得分:9)

这已经很晚了,但可能对某些人有所帮助。

我扩展了@ 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})

答案 6 :(得分:9)

我使用的一个简单方法是条件渲染:

@(Model.ExpireDate == null ? 
  @Html.TextBoxFor(m => m.ExpireDate, new { @disabled = "disabled" }) : 
  @Html.TextBoxFor(m => m.ExpireDate)
)

答案 7 :(得分:7)

使用RouteValueDictionary解决这个问题(可以像hictionary一样基于IDictionary工作)和扩展方法:

@Html.TextBoxFor(m => m.GovId, new RouteValueDictionary(new { @class = "form-control" })
.AddIf(Model.IsEntityFieldsLocked, "disabled", "disabled"))

用法:

{{1}}

信用转到https://stackoverflow.com/a/3481969/40939

答案 8 :(得分:5)

如果您不想使用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

答案 9 :(得分:4)

另一种解决方案是在调用Dictionary<string, object>之前创建TextBoxFor并传递该字典。在字典中,仅在要删除文本框时才添加"disabled"键。不是最好的解决方案,而是简单明了。

答案 10 :(得分:2)

另一种方法是禁用客户端上的文本框。

在您的情况下,您只需要禁用一个文本框,但请考虑您需要禁用多个input,select和textarea字段的情况。

通过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);
  }
}

答案 11 :(得分:0)

我喜欢扩展方法,因此您不必传递所有可能的参数。
但是,使用正则表达式可能会非常棘手(并且速度稍慢),因此我改用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)