【问题标题】:How do I make EditorFor conditionally readonly?如何使 EditorFor 有条件地只读?
【发布时间】:2015-05-23 01:54:24
【问题描述】:

我有这行代码:

@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })

我的视图数据字典中有一个名为 Readonly 的变量。如果 ViewBag.Readonly 为真,如何将 Quantity 设置为只读,如果为假,则不设置为只读?

简单的事情,但是 Razor 与 HTML(这是古老的)的结合使原本简单的事情变得不可能。

编辑:

我不想使用 if 语句。这是不得已而为之,因为它违反了 DRY,我过去曾多次因为不遵守而被严重烧伤。

我上面的那行确实有效,因为它使文本框成为只读的。我需要根据我的视图状态来设置这个条件。

解决方案:

我使用了以下内容。它仍然是 DRY 违规,但它会将其减少到一行。

@Html.EditorFor(model => model.Quantity, new { htmlAttributes = ViewBag.Readonly ? (object)new { @class = "form-control", @readonly = "htmlsucks" } : (object)new { @class = "form-control" } })

【问题讨论】:

    标签: asp.net-mvc html asp.net-mvc-5


    【解决方案1】:

    编辑:MVC 5

    控制器

    ViewBag.Readonly=true;//false
    

    查看

    @Html.EditorFor(model => model.Quantity, ViewBag.Readonly ? (object)new { htmlAttributes = new { @readonly = "readonly", @class = "form-control" }} : new { htmlAttributes = new { @class = "form-control" } })
    

    【讨论】:

    • 不错。我看到你如何最小化 DRY 违规。我尊重。我改变了一些东西,但我想我会用这个。我仍然希望有更好的选择,但这暂时有效。
    • 这是最好的答案
    • 这个问题是当你有大量htmlAttributes时,你必须重复所有其他的只是为了切换只读 ???而当你有其他属性(类似于readonly)一起独立切换时更糟糕,比如disabled,required,...所以假设这样的属性数量是n,你需要2^n表达式其他属性的重复设置。这是一个糟糕的设计。在这种情况下,最好的设计是如果属性设置为null,则忽略渲染它。 ASP.NET MVC 仍然需要更多改进。
    【解决方案2】:

    这很简单。这样做。

    @if((bool)ViewBag.Readonly)
    {
        @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
    }
    else
    {
        @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control" } })
    }
    

    【讨论】:

    • 您可以在 MVC5 中将 html 属性传递给 Html.EditorFor(我应该更清楚我使用的是哪个版本的 MVC。)我上面的代码确实使文本框只读。我不知道如何在没有 if 语句的情况下使其成为条件(再次应该更清楚,抱歉)。
    • 为什么不想使用if 语句?
    • 没问题。过去我因不遵循 DRY 原则而被烧毁。具有非常简单内容的单个两部分 if 语句似乎没什么大不了的,但随着时间的推移,它会随着您修改代码而增长。如果没有其他解决方案出现,我会这样做,但这似乎只是一个弱点,无法做到这一点。 HTML 应该使用 readonly='true|false' 而不是这个他们仍然拥有的纯名称属性废话。
    • 而且在你想做一些简单的事情(比如使字段有条件地只读)的任何地方都有这样的 if 语句真的很丑陋。我喜欢我的代码是人类可读的。我可能会看看我是否可以破解整数模板并自己执行此操作以避免这种情况。我必须弄清楚如何做到这一点。 ...
    • 我同意这很丑。但是,没有其他选择。除非,您想使用 AngularJS,如果您只想将它​​用于此目的,我认为这是完全没有必要的。
    【解决方案3】:

    今天我不得不处理这个问题,因为我必须为Html.TextBoxFor 元素动态设置一个“只读”属性。我最终编写了以下帮助方法,它允许我在保持 DRY 方法的同时解决问题:

    /// <summary>
    /// Gets an object containing a htmlAttributes collection for any Razor HTML helper component,
    /// supporting a static set (anonymous object) and/or a dynamic set (Dictionary)
    /// </summary>
    /// <param name="fixedHtmlAttributes">A fixed set of htmlAttributes (anonymous object)</param>
    /// <param name="dynamicHtmlAttributes">A dynamic set of htmlAttributes (Dictionary)</param>
    /// <returns>A collection of htmlAttributes including a merge of the given set(s)</returns>
    public static IDictionary<string, object> GetHtmlAttributes(
        object fixedHtmlAttributes = null,
        IDictionary<string, object> dynamicHtmlAttributes = null
        )
    {
        var rvd = (fixedHtmlAttributes == null)
            ? new RouteValueDictionary()
            : HtmlHelper.AnonymousObjectToHtmlAttributes(fixedHtmlAttributes);
        if (dynamicHtmlAttributes != null)
        {
            foreach (KeyValuePair<string, object> kvp in dynamicHtmlAttributes)
                rvd[kvp.Key] = kvp.Value;
        }
        return rvd;
    }
    

    可以通过以下方式使用:

    var dic = new Dictionary<string,object>();
    if (IsReadOnly()) dic.Add("readonly", "readonly");
    Html.TextBoxFor(m => m.Name, GetHtmlAttributes(new { @class="someclass" }, dic))
    

    代码是不言自明的,不过我也在博客的this post 中解释了底层逻辑。

    【讨论】:

    • 仍然相当丑陋的剃须刀代码,但我可以使用它。谢谢,我可能会创建一个翻译层,而不是字典,将readonly=true 更改为readonly="readonly" 并删除readonly=false,以便可以将只读设置为布尔值。愚蠢的 HTML 规范,带有你毫无价值的属性!这就是我们标准化接口的原因。我真希望我能回到过去,有时扇别人一巴掌。
    • @Jordan ,此解决方法的主要优点是它还可以用于动态设置其他属性设置和/或值属性(包括但不限于只读)。
    • 是的,但是 OP 的问题在于具有相当小的无价值属性。我能想到的只有readonlydisabled。如果你仔细想想,这些是唯一真正的问题。它们是唯一不能留空的属性。
    【解决方案4】:

    如果你的视图中有很多地方都有这样的逻辑,我认为使用库 FluentDataAnnotations 可以让你的代码保持干净和清晰。

    如果你熟悉FluentValidator,使用起来非常相似。

    在您的情况下,所有逻辑都将从视图移动到模型注释类。在你将只有@Html.EditorFor(model =&gt; model.Quantity)

    它甚至允许在条件下使用模型属性 例如 this.When(model => !model.AllowEditPhone, () => { this.For(m => m.Phone).SetReadOnly(false); });

    这里是需要 ASP.NET MVC 5 的 NuGet package。 (对 ASP.NET Core 的支持正在进行中。)

    【讨论】:

      【解决方案5】:

      通过编写辅助方法,可以尊重 DRY 主体。

          using System.Web.Mvc.Html;
      
          public static MvcHtmlString Concat(this MvcHtmlString first, params MvcHtmlString[] strings)
          {
              return MvcHtmlString.Create(first.ToString() + string.Concat(strings.Select(s => ( s == null ? "" : s.ToString()))));
          }
      
          public static MvcHtmlString ConditionalEditFor<TModel,TValue>(this HtmlHelper<TModel> helper, bool EditCondition, Expression<Func<TModel, TValue>> Expression)
          {
              helper.ConditionalEditFor(EditCondition,Expression,false);
          }
      
          public static MvcHtmlString ConditionalEditFor<TModel, TValue>(this HtmlHelper<TModel> helper, bool EditCondition, Expression<Func<TModel, TValue>> Expression, bool IncludeValidationOnEdit)
          {
              if (EditCondition)
              {
                  if (!IncludeValidationOnEdit)
                      return EditorExtensions.EditorFor<TModel, TValue>(helper, Expression);
                  else
                      return EditorExtensions.EditorFor<TModel, TValue>(helper, Expression).Concat(ValidationExtensions.ValidationMessageFor<TModel, TValue>(helper, Expression));
              }
              else
              {
                  return DisplayExtensions.DisplayFor<TModel, TValue>(helper, Expression);
              }
          }
      

      那么在你看来:

      添加条件语句判断只读 例如

      @{bool IsReadOnly = YourCondition;}
      
      @Html.ConditionalEditFor(!IsReadOnly/*condition*/, model => model.YourProperty,true /*do validation*/)
      

      然后您可以添加您想要的任何其他覆盖。

      【讨论】:

        【解决方案6】:

        JQUERY 读取 SETUP_TYPE 控件值并使用特定 CSS 选择器禁用控件。

        $(function () {
            if ($("#SETUP_TYPE").val() == "1") { $('.XXX').attr('disabled', true); }
        })
        
        $(function () {
            if ($("#SETUP_TYPE").val() == "2") { $('.YYY').attr('disabled', true); }
        })
        

        如果 SETUP_TYPE 为 1 或 2,则禁用此控件。

        @Html.EditorFor(model => model.CLAIM, new { htmlAttributes = new { @class = "form-control XXX YYY" } })
        

        如果 SETUP_TYPE 为 1,则禁用此控件。

        @Html.EditorFor(model => model.POLICY, new { htmlAttributes = new { @class = "form-control XXX" } })
        

        如果 SETUP_TYPE 为 2,则禁用此控件。

        @Html.EditorFor(model => model.INSURED, new { htmlAttributes = new { @class = "form-control YYY" } })
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-26
          • 1970-01-01
          • 2019-10-01
          • 1970-01-01
          相关资源
          最近更新 更多