ASP.NET MVC中EditorFor()的HTML属性


129

为什么我不能将html属性传递给EditorFor()?例如;

<%= Html.EditorFor(model => model.Control.PeriodType, 
    new { disabled = "disabled", readonly = "readonly" }) %>

我不想使用元数据

更新:解决方案是从视图中调用此方法:

 <%=Html.EditorFor( model => model.Control.PeriodEndDate, new {Modifiable=model.Control.PeriodEndDateModifiable})%>

ViewData["Modifiable"]在我的自定义EditorTemplates / String.ascx中使用,其中我具有一些视图逻辑,该逻辑确定是否将只读和/或禁用的属性添加到输入中。传入的匿名对象EditorFor()是一个名为的参数additionalViewData,其属性将传递到ViewData采集。


19
严重的是,在MVC3中仍然没有此限制,这确实很烦人。世界各地的人们都在浪费时间,胡说八道。我将其发送到Microsoft Connect。
JuniorMayhé2012年


3
是我一个人,还是一些简单的东西看起来像很多bs?
埃里克K

也许这会对您有所帮助:[带有CSS类和HTML属性的EditorFor-Implementation] [1] [1]:stackoverflow.com/questions/12675708/…–
FunThom

Answers:


96

EditorFor与元数据一起使用,因此,如果您想添加html属性,则可以始终这样做。另一种选择是简单地编写自定义模板并使用TextBoxFor

<%= Html.TextBoxFor(model => model.Control.PeriodType, 
    new { disabled = "disabled", @readonly = "readonly" }) %>    

元数据将不起作用,因为html属性取决于模型中的其他属性,换句话说,域或viemodel逻辑应确定html属性而不是静态元数据。还是我错过了要点,我可以动态设置元数据吗?
Typo Johnson

什么PeriodType啊 这不是简单的财产吗?如果它是一个复杂的对象,则可以通过将一部分放置在属性的类型名称~/Views/ControllerName/EditorTemplates/SomeType.ascx所在的位置来自定义整个模板。SomeTypePeriodType
Darin Dimitrov 2010年

同样,您建议的代码将意味着将整个模型传递到访问特定属性的局部模板中,这意味着每个属性都具有局部属性?
Typo Johnson

2
我现在知道了 我可以使用<%= Html.EditorFor(model => model.Control.PeriodEndDate,new {Modifiable = model.Control.PeriodEndDateModifiable})%>并在我的自定义EditorTemplates / String.ascx中使用ViewData [“ PeriodEndDateModifiable”]。谢谢
Typo Johnson

1
@JuniorMayhé,我不会将其称为无聊的限制。如果您仔细考虑一下,您将理解这是有道理的。实际上,EditorFor帮助程序的全部要点是您可以拥有一个相应的模板。该模板可以包含任何标记。不一定是单个元素。例如,定义@class一个包含3个div的编辑器模板绝对没有任何意义。Html.TextBoxFor帮助程序允许您定义它,因为您知道此帮助程序生成的内容-一个文本框,因此有必要为输入元素定义一个类。
Darin Dimitrov

115

Update MVC 5.1现在直接支持以下方法,因此它也适用于内置编辑器。http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (这是Great mind的思考方式,或者他们阅读了我的回答:)

结束更新

如果您使用自己的编辑器模板或使用MVC 5.1,则现在直接为内置编辑器支持以下方法。

@Html.EditorFor(modelItem => item.YourProperty, 
  new { htmlAttributes = new { @class="verificationStatusSelect", style = "Width:50px"  } })

然后在您的模板中(MVC 5.1中的简单类型不需要)

@Html.TextBoxFor(m => m, ViewData["htmlAttributes"])

5
这项新功能完美解决了四年前提出的原始问题。
CoderSteve 2014年

1
如果我使用大量的自定义编辑器模板代替TextBoxFor和类似的助手,我不会说将ViewData [...]添加到每个模板中是一个绝妙的主意... :(
亚历山大

42

从MVC 5.1开始,您现在可以执行以下操作:

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

http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features


上面的链接无效。这在MVC 5.1中可用,更多信息在这里:asp.net/mvc/overview/releases/mvc51-release-notes#new-features
Alaa Masoud

1
谢谢,我也修复了链接。
vtforester 2014年

2
如何合并htmlAttributes?
Bart Calixto 2014年

这仅适用于内置/默认EditorFor模板。如果您自己实现,则必须遵循AntonK的回答。
mxmissile

6

现在,ASP.Net MVC 5.1获得了对它的内置支持。

从发行说明中

现在,我们允许在EditorFor中将HTML属性作为匿名对象传递。

例如:

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

4

这是MVC 5.1 Editor中html属性VB.Net代码语法

@Html.EditorFor(Function(x) x.myStringProp, New With {.htmlAttributes = New With {.class = "myCssClass", .maxlength="30"}}))

3

为什么不只是使用

@Html.DisplayFor(model => model.Control.PeriodType)

30
原因之一是DisplayFor不呈现输入,因此该值在回发时丢失。
ProfK 2012年

2
另一个原因是在特定情况下,编辑器当前处于锁定状态,但并非始终处于锁定状态,并且您想传达的数据可能是可编辑的-只是现在不行。
Mir

2

如果您不想使用元数据,则可以使用[UIHint("PeriodType")]属性来修饰属性,如果属性是复杂类型,则不必修饰任何内容。然后,EditorFor将在EditorTemplates文件夹中查找PeriodType.aspx或ascx文件,并改用该文件。


谢谢,如果仅在某些字段中需要编辑器模板中的if / else,我可能最终会这样做
Typo Johnson

我虽然你说过你不能改变模型(不是你的代码),所以直接用UIHint装饰不是一种选择。
Darrel Lee 2012年

2

今天,我一直在努力解决与绑定到可为null的布尔绑定的复选框的问题,并且由于我无法更改模型(不是代码),因此我不得不想出一种更好的方法来处理此问题。这有点蛮力,但是在我可能遇到的99%的情况下,它应该可以工作。您显然必须为每种输入类型进行一些有效属性的手动填充,但是我想我已经将所有所有属性都选中了。

在我的Boolean.cshtml编辑器模板中:

@model bool?

@{
    var attribs = new Dictionary<string, object>();
    var validAttribs = new string[] {"style", "class", "checked", "@class",
        "classname","id", "required", "value", "disabled", "readonly", 
        "accesskey", "lang", "tabindex", "title", "onblur", "onfocus", 
        "onclick", "onchange", "ondblclick", "onmousedown", "onmousemove", 
        "onmouseout", "onmouseover", "onmouseup", "onselect"};
    foreach (var item in ViewData) 
    {
        if (item.Key.ToLower().IndexOf("data_") == 0 || item.Key.ToLower().IndexOf("aria_") == 0) 
        {
            attribs.Add(item.Key.Replace('_', '-'), item.Value);
        } 
        else 
        {
            if (validAttribs.Contains(item.Key.ToLower()))
            {
                attribs.Add(item.Key, item.Value);
            }
        }
    }
}

@Html.CheckBox("", Model.GetValueOrDefault(), attribs)

我加了Dictionary<string,string> attribs = new Dictionary<string,string>();attribs.Add("tabindex","16");在其中的一个@( )在我的页面的顶部块。然后,我@Html.CheckBox("IsActive", Model.IsActive.HasValue ? Model.IsActive : false, attribs)在页面上操作,它给了我一个错误:“'System.Web.Mvc.HtmlHelper <MyProject.Models.MyObject>'不包含'CheckBox'的定义,而最佳扩展方法重载'System.Web。 Mvc.InputExtensions.CheckBox(System.Web.Mvc.HtmlHelper,string.bool,object)'具有一些无效的参数”。
vapcguy 2014年

2

您仍然可以使用EditorFor。只需将style / html属性作为ViewData传递即可。

@Html.EditorFor(model => model.YourProperty, new { style = "Width:50px" })

因为EditorFor使用模板进行渲染,所以您可以覆盖属性的默认模板,只需将style属性作为ViewData传递即可。

因此,您的EditorTemplate需要以下内容:

@inherits System.Web.Mvc.WebViewPage<object>

@Html.TextBoxFor(m => m, new { @class = "text ui-widget-content", style=ViewData["style"] })

1
Html.TextBoxFor(model => model.Control.PeriodType, 
    new { @class="text-box single-line"})

你可以这样使用; 与相同的输出Html.EditorFor,您可以添加html属性


除了TextBoxFor忽略DisplayFormat您尝试应用的任何类型。
埃里克K

1

只需在Views / Shared / EditorTemplates / MyTypeEditor.vbhtml中为类型创建自己的模板

@ModelType MyType

@ModelType MyType
@Code
    Dim name As String = ViewData("ControlId")
    If String.IsNullOrEmpty(name) Then
        name = "MyTypeEditor"
    End If
End Code

' Mark-up for MyType Editor
@Html.TextBox(name, Model, New With {.style = "width:65px;background-color:yellow"})

使用model属性从您的视图中调用编辑器:

@Html.EditorFor(Function(m) m.MyTypeProperty, "MyTypeEditor", New {.ControlId = "uniqueId"})

请原谅VB语法。那就是我们滚动的方式。


1

以我为例,我试图创建一个可以接收其他属性的HTML5数字输入编辑器模板。更加巧妙的方法是编写您自己的HTML Helper,但是由于我已经有了.ascx模板,因此我采用了这种方法:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<input id="<%= Regex.Replace(ViewData.TemplateInfo.GetFullHtmlFieldId(""), @"[\[\]]", "_") %>" name="<%= ViewData.TemplateInfo.HtmlFieldPrefix %>" type="number" value="<%= ViewData.TemplateInfo.FormattedModelValue %>"
<% if (ViewData["attributes"] != null)
   {
       Dictionary<string, string> attributes = (Dictionary<string, string>)ViewData["attributes"];
       foreach (string attributeName in attributes.Keys){%>
        <%= String.Format(" {0}=\"{1}\"", attributeName, attributes[attributeName])%>
       <% }
   } %> />

这个丑陋的位会创建一个数字类型的输入,并查找带有键“ attributes”的ViewData字典。它将遍历字典,将其键/值对添加为属性。ID属性中的Regex是无关的,并且存在于此,因为在集合中使用时,它GetFullHtmlFieldId()返回一个包含方括号的ID [],通常会将其作为下划线转义。

然后将该模板称为:

Html.EditorFor(m => m.Quantity, "NumberField", new { attributes = new Dictionary<string, string>() { { "class", "txtQuantity" } } }

详细,但有效。您可能在模板中使用反射将属性名称用作属性名称,而不是使用字典。


1

ViewData在控制器中使用设置条件

ViewData["Modifiable"] = model.recProcessed;

然后在编辑器模板中使用此viewdata设置控件的html属性

@Html.RadioButton(prefix, li.Value, li.Selected, @ViewData["Modifiable"].ToString().ToLower() == "true" ? (object)new  { @id = li.Value, @disabled = "disabled" } : new { @id = li.Value })

0

MVC 5.1和更高版本的解决方案(将合并本地HtmlAttributes并在EditorTemplates中定义):

共享\ EditorTemplates \ String.cshtml:

@Html.TextBoxFor(model => model, new { @class = "form-control", placeholder = ViewData.ModelMetadata.Watermark }.ToExpando().MergeHtmlAttributes(ViewData["htmlAttributes"].ToExpando()))

扩充功能:

public static IDictionary<string, object> MergeHtmlAttributes(this ExpandoObject source1, dynamic source2)
{
    Condition.Requires(source1, "source1").IsNotNull().IsLongerThan(0);

    IDictionary<string, object> result = source2 == null
        ? new Dictionary<string, object>()
        : (IDictionary<string, object>) source2;

    var dictionary1 = (IDictionary<string, object>) source1;

    string[] commonKeys = result.Keys.Where(dictionary1.ContainsKey).ToArray();
    foreach (var key in commonKeys)
    {
        result[key] = string.Format("{0} {1}", dictionary1[key], result[key]);
    }

    foreach (var item in dictionary1.Where(pair => !result.ContainsKey(pair.Key)))
    {
        result.Add(item);
    }

    return result;
}

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var item in anonymousDictionary)
        expando.Add(item);
    return (ExpandoObject)expando;
}

public static bool HasProperty(this ExpandoObject expando, string key)
{
    return ((IDictionary<string, object>)expando).ContainsKey(key);
}

用法:

@Html.EditorFor(m => m.PromotionalCode, new { htmlAttributes = new { ng_model = "roomCtrl.searchRoomModel().promoCode" }})

1
谢谢,那行得通。除了所有data_xxx属性外,在强制转换source1source2as 时必须将_替换为- IDictionary<string, object>。我设定了以下功能: private static IDictionary<string, object> ToHtmlAttributesDictionary(this IEnumerable<KeyValuePair<string, object>> dico) { return dico.ToDictionary(s => s.Key.Replace('_', '-'), s => s.Value); }
Marien Monnier 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.