Asp.net mvc MVC 3:有条件地使用HtmlHelpers添加Disabled属性

Asp.net mvc MVC 3:有条件地使用HtmlHelpers添加Disabled属性,asp.net-mvc,asp.net-mvc-3,html-helper,Asp.net Mvc,Asp.net Mvc 3,Html Helper,我有一个ASP.NETMVC3Web应用程序,我正在使用HtmlHelper类向视图页面添加一个复选框,如下所示 @Html.CheckBox("CheckBox1", true, new { @class = "Class1" }) 我想做的是根据视图状态属性有条件地添加disabled属性。基本上以下是理想的 @Html.CheckBox("CheckBox1", true, new { @class = "Class1", @disabled = Model.ReadOnly }) 不

我有一个ASP.NETMVC3Web应用程序,我正在使用HtmlHelper类向视图页面添加一个复选框,如下所示

@Html.CheckBox("CheckBox1", true, new { @class = "Class1" })
我想做的是根据视图状态属性有条件地添加disabled属性。基本上以下是理想的

@Html.CheckBox("CheckBox1", true, new { @class = "Class1", @disabled = Model.ReadOnly })
不幸的是,由于禁用属性的性质,这将不起作用,因为分配给禁用属性的任何值(甚至“false”)都将转换为true

我已经想到了一些解决这个问题的办法,所以问题不在于我如何才能做到这一点。但是,有没有一种简单的方法像上面想要的方法?或者我必须求助于下列方法之一

我知道我能做什么

  • 创建if/else语句并写入不同的
    Html.CheckBox
    行(可读性不好-可能会抛出标记警告-不确定)

  • 跳过HtmlHelper类并手工编写标记,以获得更好的条件属性(使代码更短,但增加了不一致性)

  • 创建一个接受“disabled”参数的自定义帮助器(这是最干净的解决方案,但需要不需要的额外方法-可能是目前为止最好的选择)


  • 在视图/帮助程序中的某个位置定义此项

    @functions {
     object getHtmlAttributes (bool ReadOnly, string CssClass) 
     {
         if (ReadOnly) {
             return new { @class = CssClass, @readonly = "readonly" };
         }
         return new { @class = CssClass };
     }
    }
    
    然后使用:

    @Html.TextBox("name", "value", @getHtmlAttributes(Model.ReadOnly, "test"))
    

    下面是我对这个类似问题的回答:


    我创建了以下帮助器-它接受一个布尔值和一个匿名对象。如果disabled为true,则将disabled属性添加到值为“disabled”的匿名对象(实际上是一个字典),否则根本不添加属性

    public static RouteValueDictionary ConditionalDisable(
       bool disabled, 
       object htmlAttributes = null)
    {
       var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    
       if (disabled)
          dictionary.Add("disabled", "disabled");
    
       return dictionary;
    }
    
    这方面的一个例子是:

    @Html.TextBoxFor(m => m.SomeProperty,    
       HtmlHelpers.ConditionalDisable(true, new { @class = "someClass"))
    
    对我来说,这种方法的一个巨大优势是,它几乎适用于所有MVC HTMLHelper,因为它们都有接受RouteValueDictionary而不是匿名对象的重载

    注意事项
    HtmlHelper.AnonymousObjectToHtmlatAttributes()
    使用一些奇特的代码忍者工作来完成任务。我不完全确定它的性能如何。。。但这已经足够我用它做什么了。您的里程可能会有所不同

    我并不特别喜欢它的名字,但我想不出更好的名字了。重命名很容易


    我也不喜欢使用语法,但我还是想不出更好的方法。这应该不难改变。对象的扩展方法是一种思想。。。您将以
    new{@class=“someClass”}.ConditionalDisable(true)
    结束,但是如果您只想要disable属性,并且没有任何附加内容,那么您将以类似
    new{}.ConditionalDisable(true)的东西结束并且您还将得到一个扩展方法,该方法将显示所有
    对象
    。。。这可能是不可取的。

    如果您想要更简洁的语法而不需要helper函数,那么在定义用于@html.Checkbox helper的html属性的字典时,可以使用三元语句

    @Html.CheckBox("CheckBox1", true, Model.ReadOnly 
           ? new { @class = "Class1", @disabled = Model.ReadOnly } 
           : null)
    

    在本例中,is Model.ReadOnly为false,null作为html属性的字典传递。

    执行添加禁用属性客户端的操作对我有效。注意:您应该检查哪些字段允许在服务器端进行编辑,但对于以装饰性方式声明禁用属性的情况也是如此

    在本例中,我使用jQuery禁用了表单的所有子元素

        if (Model.CanEdit)
        {
            <script type="text/javascript">
    
                $(document).ready(function() {
    
                    $('#editForm *').attr('disabled', true);
                });
    
            </script>
        }
    
    if(Model.CanEdit)
    {
    $(文档).ready(函数(){
    $('editForm*').attr('disabled',true);
    });
    }
    
    @Html.TextBoxFor(m=>m.FieldName,Html.fixBoolatAttributes(新){
    @class=“myClass”,
    @readonly=myFlag
    }))
    公共静态类BooleanAttributeFix
    {
    /// 
    ///规范化HTML布尔属性,使readonly=true变为readonly=“readonly”,并
    ///readonly=false将完全删除该属性。
    /// 
    /// 
    /// 
    /// 
    公共静态RouteValueDictionary FixBoolatAttributes(此HtmlHelper HtmlHelper,对象htmlAttributes)
    {
    var attrs=HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    foreach(新[]{“disabled”,“readonly”}中的var attrName)
    {
    目标价值;
    if(attrs.TryGetValue(attrName,out值))
    {
    如果(真实性(值))
    {
    //从readonly=“true”更改为readonly=“readonly”
    attrs[attrName]=attrName;
    }
    其他的
    {
    //完全删除属性
    attrs.Remove(attrName);
    }
    }
    }
    返回属性;
    }
    /// 
    ///对于值是否为真,应用类似于javascript的松散规则。
    ///例如,1=true,非空字符串=true等等。
    /// 
    /// 
    /// 
    私有静态布尔值(对象值)
    {   
    if(val==null)
    返回false;
    if(val是字符串)
    {
    return!String.IsNullOrEmpty((String)val);
    }
    类型t=val.GetType();
    if(t.IsValueType&&Nullable.GetUnderlineType(t)==null)
    {
    //如果是不可为null的值类型,如int,则需要检查
    //默认值,例如0。
    object defaultValue=Activator.CreateInstance(t);
    //使用.Equals比较值,而不是要比较的==值
    //值而不是装箱对象。
    //看http://stackoverflow.com/questions/6205029/comparing-boxed-value-types
    return!val.Equals(默认值);
    }
    返回true;
    }
    }
    
    您认为我的简单解决方案怎么样?它可以轻松处理两种可能的
    HtmlAttributes
    类型:

    • 字典
    • 匿名
      @Html.TextBoxFor(m => m.FieldName, Html.FixBoolAttributes(new {
          @class = "myClass",
          @readonly = myFlag  
      }))
      
      
      public static class BooleanAttributeFix
      {
          /// <summary>
          /// Normalises HTML boolean attributes so that readonly=true becomes readonly="readonly" and
          /// readonly=false removes the attribute completely.
          /// </summary>
          /// <param name="htmlHelper"></param>
          /// <param name="htmlAttributes"></param>
          /// <returns></returns>
          public static RouteValueDictionary FixBoolAttributes(this HtmlHelper htmlHelper, object htmlAttributes)
          {
              var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
      
              foreach(var attrName in new[] { "disabled", "readonly" })
              {
                  object value;
                  if(attrs.TryGetValue(attrName, out value))
                  {
                      if(isTruthy(value))
                      {
                          // Change from readonly="true" to readonly="readonly"
                          attrs[attrName] = attrName; 
                      }
                      else
                      {
                          // Remove attribute entirely
                          attrs.Remove(attrName); 
                      }
                  }
              }
              return attrs;
          }
      
          /// <summary>
          /// Apply similar loose rules like javascript does for whether a value is true or not.
          /// e.g. 1 = true, non-empty string = true and so on.
          /// </summary>
          /// <param name="val"></param>
          /// <returns></returns>
          private static bool isTruthy(object val)
          {   
              if(val == null)
                  return false;
      
              if(val is string)
              {
                  return !String.IsNullOrEmpty((string)val);
              }
      
              Type t = val.GetType();
      
              if(t.IsValueType && Nullable.GetUnderlyingType(t) == null)
              {
                  // If a non-nullable value type such as int we want to check for the
                  // default value e.g. 0.
                  object defaultValue = Activator.CreateInstance(t);
      
                  // Use .Equals to compare the values rather than == as we want to compare
                  // the values rather than the boxing objects.
                  // See http://stackoverflow.com/questions/6205029/comparing-boxed-value-types
                  return !val.Equals(defaultValue);
              }
      
              return true;
          }
      }
      
      public static class HtmlAttributesExtensions
      {
          public static IDictionary<string, object> AddHtmlAttrItem(this object obj, string name, object value, bool condition)
          {
              var items= !condition ? new RouteValueDictionary(obj) : new RouteValueDictionary(obj) {{name, value}};
              return UnderlineToDashInDictionaryKeys(items);
          }
          public static IDictionary<string, object> AddHtmlAttrItem(this IDictionary<string, object> dictSource, string name, object value, bool condition)
          {
              if (!condition)
                  return dictSource;
      
              dictSource.Add(name, value);
              return UnderlineToDashInDictionaryKeys(dictSource);
          }
          private static IDictionary<string, object> UnderlineToDashInDictionaryKeys(IDictionary<string,object> items)
          {
              var newItems = new RouteValueDictionary();
              foreach (var item in items)
              {
                  newItems.Add(item.Key.Replace("_", "-"), item.Value);
              }
              return newItems;
          }
      }
      
      @{
        var hasDisabled=true; 
      }
      
      @Html.CheckBox("CheckBox1"
                    , true
                    , new { @class = "Class1"}
                     .AddHtmlAttrItem("disabled", "disabled", hasDisabled))
      .
      
      @Html.CheckBox("CheckBox1"
                    , true
                    , new Dictionary<string, object> { { "class", "Class1" }
                     .AddHtmlAttrItem("disabled", "disabled", hasDisabled))
      .
      
      @{
        var hasDisabled=true;
        var hasMax=false ;
        var hasMin=true ;
      }
      
      @Html.CheckBox("CheckBox1"
                    , true
                    , new { @class = "Class1"}
                     .AddHtmlAttrItem("disabled", "disabled", hasDisabled)
                     .AddHtmlAttrItem("data-max", "100", hasMax)
                     .AddHtmlAttrItem("data-min", "50", hasMin))
      .
      
      <script type="text/javascript">
          var list, index;
          list = document.getElementsByClassName("form-control");
          for (index = 0; index < list.length; ++index) {
              list[index].setAttribute('disabled', true);
          }
      </script>