MVC 3:使用HtmlHelpers有条件地添加已禁用的属性
我有一个ASP.Net MVC 3的Web应用程序,我正在添加一个checkbox使用HtmlHelper类的视图页面,像这样…
@Html.CheckBox("CheckBox1", true, new { @class = "Class1" })
我想要做的是有条件地添加基于视图状态属性的禁用属性。 基本上下面是理想的…
@Html.CheckBox("CheckBox1", true, new { @class = "Class1", @disabled = Model.ReadOnly })
不幸的是,由于禁用属性的性质,这将无法正常工作,因为任何分配给被禁用属性的值(甚至“false”)都将被翻译为true。
我已经想到了解决这个问题的一些解决scheme,所以问题不是我怎么能做到这一点。 但是,有没有像上面所需的方法一个简单的方法? 还是我不得不诉诸以下之一?
我知道我可以做…
-
创build一个if / else语句并写入不同的
Html.CheckBox
行(不是很好的可读性 – 可能抛出一个标记警告 – 不知道) -
跳过HtmlHelper类并手写标签,以允许更好的条件属性(保持代码更短,但添加不一致)
-
创build一个自定义的助手,它需要一个“禁用”参数(最干净的解决scheme,但需要不必要的额外方法 – 尽pipe目前为止可能是最好的select)
在你的视图/助手中定义这个地方
@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"))
这是我从这个类似的问题的答案: https : //stackoverflow.com/a/13922813/495000
我创build了以下帮助器 – 它需要一个布尔值和一个匿名对象。 如果禁用为true,则将disabled属性添加到匿名对象(实际上是Dictionary),值为“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 HtmlHelpers一起工作,因为它们都具有接受RouteValueDictionary而不是匿名对象的Overload。
注意事项 :
HtmlHelper.AnonymousObjectToHtmlAttributes()
使用一些奇特的代码忍者工作来完成任务。 我不完全确定它的性能如何……但是对于我使用它的已经足够了。 你的旅费可能会改变。
我不是特别喜欢它的名字 – 但是我不能拿出更好的东西。 重命名很简单。
我也不喜欢使用的语法 – 但我再也找不到更好的东西了。 改变应该不难。 对象的扩展方法是一个想法…你最终会得到new { @class = "someClass" }.ConditionalDisable(true)
但是如果你只想禁用属性,并没有任何额外的东西来添加你最终得到的结果就像new {}.ConditionalDisable(true);
而且你最终还得到一个扩展方法,它显示所有的object
…这可能是不可取的。
如果你想要更简洁的语法而不需要帮助函数,那么在定义用于@ HTML.Checkbox助手的html属性的字典时,可以使用三元语句。
@Html.CheckBox("CheckBox1", true, Model.ReadOnly ? new { @class = "Class1", @disabled = Model.ReadOnly } : null)
在这种情况下,Model.ReadOnly为false,null作为html属性的字典传递。
执行添加禁用的属性客户端工作适合我。 请注意,您应该检查哪些字段被允许在服务器端进行编辑,但是对于禁用的属性的装饰位置也是如此。
在这个例子中,我使用jQuery禁用了一个窗体的所有childeren。
if (Model.CanEdit) { <script type="text/javascript"> $(document).ready(function() { $('#editForm *').attr('disabled', true); }); </script> }
@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. /// eg 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 eg 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; } }
你怎么看待我的简单解决scheme? 它可以轻松地使用两种可能的HtmlAttributes
types:
-
Dictionary<string, object>
-
Anonymous Object
:
首先将以下简单的extension class
添加到您的项目中:
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; } }
现在在视图中:
示例1 ( HtmlAttributes
types为Anonymous Object
)
@{ var hasDisabled=true; } @Html.CheckBox("CheckBox1" , true , new { @class = "Class1"} .AddHtmlAttrItem("disabled", "disabled", hasDisabled)) .
示例2 ( HtmlAttributes
types为Dictionary<string, object>
)
@Html.CheckBox("CheckBox1" , true , new Dictionary<string, object> { { "class", "Class1" } .AddHtmlAttrItem("disabled", "disabled", hasDisabled)) .
现在只需将
makeItReadOnly
值更改为false
!
示例3 (多个条件属性)
@{ 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)) .