【问题标题】:Conditionally disable Html.DropDownList有条件地禁用 Html.DropDownList
【发布时间】:2010-01-18 21:48:19
【问题描述】:

如何更改此 DropDownList 声明,以便有条件地启用/禁用 disabled 属性?

<%= Html.DropDownList("Quantity", new SelectList(...), new{@disabled="disabled"} %>

非工作示例:

<%= Html.DropDownList("Quantity", new SelectList(...), new{@disabled=Model.CanEdit?"false":"disabled"} %>

附言在整个语句周围添加 if 条件不是理想的方法:)

编辑:基于另一个问题的this 扩展方法,我想出了以下扩展:

public static IDictionary<string, object> Disabled (this object obj, bool disabled)
{
  return disabled ? obj.AddProperty ("disabled", "disabled") : obj.ToDictionary ();
}

然后可以用作

<%= Html.DropDownList("Quantity", new SelectList(...), new{id="quantity"}.Disabled(Model.CanEdit) %>

【问题讨论】:

  • 嗨,我想仅根据值禁用/启用特定页面的下拉列表,我将其传递给模型。我尝试将 true / false 传递给残疾人,但它不起作用。你能帮忙吗

标签: asp.net-mvc


【解决方案1】:

无需添加辅助方法,直接使用即可

<%= Html.DropDownList("Quantity", new SelectList(...), IsEditable == true ? new { @disabled = "disabled" } as object : new {} as object %>

如果您要删除 as object 条目,这将不起作用,因为默认情况下 new {} 是在运行时编译的动态对象,因此两个可能的对象必须具有相同的属性。但是 Html attributes 参数实际上只是一个对象,因此可以将这些动态转换为对象来解决这个问题。

此解决方案甚至允许您使用多个 HTML 属性,其中一个是可选的,另一个不是,即 class='whatever' 不是可选的,但 disabled 是,所以您将 class='whatever' 放在两个对象中,但只有可选的一个在第一个。 Dimitrov 的回答不支持除禁用以外的任何自定义属性。

【讨论】:

  • 可能这是一个最简单的解决方案,但是代码是如此的不可读和丑陋,它伤害了我的眼睛。如果你有一些其他的属性参数,它会变得更加丑陋。所以 IMO 这不是最佳答案。
【解决方案2】:

请不要编写意大利面条式代码。用于此目的的 Html 助手:

public static MvcHtmlString DropDownList(this HtmlHelper html, string name, SelectList values, bool canEdit)
{
    if (canEdit)
    {
        return html.DropDownList(name, values);
    }
    return html.DropDownList(name, values, new { disabled = "disabled" });
}

然后:

<%= Html.DropDownList("Quantity", new SelectList(...), Model.CanEdit) %>

或者也许你可以想出更好的东西(如果模型包含选项):

<%= Html.DropDownList("Quantity", Model) %>

您还将获得拥有更多可单元测试代码的好处。

【讨论】:

  • 由于 WebForms 引擎的特性,您不能对视图进行单元测试。您可以测试扩展方法。这样,您的视图将不再包含值得单元测试的条件逻辑。通过测试扩展方法,您可以确保使用它的所有视图都按照您的预期运行,并且根据模型上的 CanEdit 属性具有准确的标记。
  • 如果我需要带有这个签名的辅助方法,这段代码会是什么样子? public static string DropDownList(this HtmlHelper html, string name, SelectList values, object htmlAttributes, bool canEdit)
  • @Pavel Surmenok,您可以使用 DropDownList 重载,它采用 RouteValueDictionary 允许您将 html 属性合并在一起。
【解决方案3】:

一种选择是创建一个自定义版本的 Html.DropDownList,它需要一个额外的参数并执行您想要的操作......但是您必须为每种类型的帮助器创建一个新版本 - TextBoxFor、TextAreaFor、CheckBoxFor 等......你仍然必须弄清楚如何让它发挥作用。

相反,我选择创建一个 Html Helper 来替换普通的匿名 HtmlAttributes 对象,因为这样它就可以与所有使用 HtmlAttributes 的 Helper 兼容,而无需任何特殊工作。此解决方案还允许您传递其他属性,例如类、名称或任何您想要的。它不会将您锁定为仅禁用。

我创建了以下 Helper - 它需要一个布尔值和一个匿名对象。如果 disabled 为真,它会将 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.AnonymousObjectToHtmlAttributes() 使用一些花哨的代码忍者工作来完成任务。我不完全确定它的性能如何......但对于我使用它来说已经足够了。您的里程可能会有所不同。

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

我也不喜欢使用语法——但我还是想不出更好的办法。改变应该不难。 object 上的扩展方法是一个想法......你最终会得到 new { @class = "someClass" }.ConditionalDisable(true) 但是如果你只想要禁用属性并且没有任何额外的东西可以添加你最终会得到像 new {}.ConditionalDisable(true); 这样的恶心的东西而且您最终还会得到一个显示所有对象的扩展方法......这可能是不可取的。

【讨论】:

  • 这是唯一一个考虑传递多个 htmlAttributes 的可能性并且适用于所有 HtmlHelpers 的答案。竖起大拇指。
【解决方案4】:
@bool IsEditable=true;

@if (IsEditable)
{
    Html.DropDownListFor(m => m, selectList);
}
else
{
    Html.DropDownListFor(m => m, selectList, new { disabled = "disabled" })
}

【讨论】:

    【解决方案5】:

    强类型版本:

     public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel>    html,
                                                                       Expression<Func<TModel, TProperty>> expression,
                                                                       IEnumerable<SelectListItem> selectList,
                                                                       string optionText, bool canEdit)
        {
            if (canEdit)
            {
                return html.DropDownListFor(expression, selectList, optionText);
            }
            return html.DropDownListFor(expression, selectList, optionText, new { disabled = "disabled" });
        }
    

    【讨论】:

      【解决方案6】:

      为了完整起见,这里保留了所有参数,并将选择值发布到服务器:

      public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, object htmlAttributes, bool enabled)
      {
        if (enabled)
        {
          return SelectExtensions.DropDownListFor<TModel, TProperty>(html, expression, selectList, htmlAttributes);
        }
      
        var htmlAttributesAsDict = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        htmlAttributesAsDict.Add("disabled", "disabled");
        string selectClientId = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(ExpressionHelper.GetExpressionText(expression));
        htmlAttributesAsDict.Add("id", selectClientId + "_disabled");
      
        var hiddenFieldMarkup = html.HiddenFor<TModel, TProperty>(expression);
        var selectMarkup = SelectExtensions.DropDownListFor<TModel, TProperty>(html, expression, selectList, htmlAttributesAsDict);
        return MvcHtmlString.Create(selectMarkup.ToString() + Environment.NewLine + hiddenFieldMarkup.ToString());
      }
      

      使用示例,如果列表中只有一项,则禁用下拉菜单,该值仍会以正确的客户端 ID 发布到服务器:

      @Html.DropDownListFor(m => m.SomeValue, Model.SomeList, new { @class = "some-class" }, Model.SomeList > 1)
      

      【讨论】:

        【解决方案7】:

        你可以这样做:

        var dropDownEditDisable = new { disabled = "disabled" };
        var dropDownEditEnable = new { };
        
        object enableOrDisable = Model.CanEdit ? 
                   (object)dropDownEditEnable : (object)dropDownEditDisable;
        
        @Html.DropDownList("Quantity", new SelectList(...), enableOrDisable)
        

        Html.DropDownListFor() 可以很长,这样就不用重复了。

        【讨论】:

          【解决方案8】:

          我不知道 ASP.NET 是否提供更简洁的特殊情况方法,但大概您可以这样做:

          <%= Html.DropDownList("Quantity", new SelectList(...), Model.CanEdit? new{@class="quantity"} : new{@class="quantity", @disabled:"disabled"}) %>
          

          【讨论】:

          • 不,你不能那样做。您收到编译时错误:“无法确定条件表达式的类型,因为 'AnonymousType#1' 和 'AnonymousType#2' 之间没有隐式转换”
          • 您需要将强制转换添加到 anonymousTypes 'as object' 才能正常工作
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-28
          • 2012-02-23
          • 1970-01-01
          • 1970-01-01
          • 2016-10-31
          相关资源
          最近更新 更多