有条件地禁用Html.DropDownList

时间:2010-01-18 21:48:19

标签: asp.net-mvc

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

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

非工作示例:

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

P.S。在整个语句中添加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) %>

8 个答案:

答案 0 :(得分:27)

无需添加辅助方法,只需使用

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

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

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

答案 1 :(得分:19)

请不要写意大利面条代码。 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) %>

您还将获得更多单元可测试代码的奖励。

答案 2 :(得分:9)

一个选项是创建一个Html.DropDownList的自定义版本,它接受一个额外的参数并做你想要的...但是你必须为每种类型的帮助器创建一个新的 - TextBoxFor,TextAreaFor,CheckBoxFor等......你仍然需要弄清楚如何使它的内脏发挥作用。

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

我创建了以下Helper - 它需要一个布尔值和一个匿名对象。如果disabled为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 HtmlHelper,因为它们都具有接受RouteValueDictionary而不是匿名对象的Overload。

<强>注意事项
HtmlHelper.AnonymousObjectToHtmlAttributes()使用一些奇特的代码忍者工作来完成工作。我不完全确定它的性能如何......但它足以满足我的需求。您的里程可能会有所不同。

我并不特别喜欢它的名字 - 但我无法想出更好的东西。重命名很容易。

我也不喜欢使用语法 - 但是我再也找不到更好的了。改变应该不难。 object上的扩展方法是一个想法...你最终会得到new { @class = "someClass" }.ConditionalDisable(true)但是如果你只想要禁用属性并且没有任何额外的东西可以添加,那么你最终会得到一些粗略的东西比如new {}.ConditionalDisable(true);,你最终会得到一个显示所有对象的扩展方法......这可能是不可取的。

答案 3 :(得分:2)

@bool IsEditable=true;

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

答案 4 :(得分:0)

强类型的verison:

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

答案 5 :(得分:0)

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

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)

答案 6 :(得分:0)

您可以这样做:

var dropDownEditDisable = new { disabled = "disabled" };
var dropDownEditEnable = new { };

object enableOrDisable = Model.CanEdit ? 
           (object)dropDownEditEnable : (object)dropDownEditDisable;

@Html.DropDownList("Quantity", new SelectList(...), enableOrDisable)

Html.DropDownListFor()可以很长,因此无需重复。

答案 7 :(得分:-2)

我不知道ASP.NET是否提供了更简洁的特殊情况方法,但可能你可以做到:

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