ASP.NET MVC'de EditorFor () için html öznitelikleri


129

Neden html özniteliklerini 'a aktaramıyorum EditorFor()? Örneğin;

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

Meta verileri kullanmak istemiyorum

Güncelleme : Çözüm, bunu görünümden çağırmaktı:

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

ve ViewData["Modifiable"]girdiye salt okunur ve / veya devre dışı bırakılmış özniteliklerin eklenip eklenmeyeceğini belirleyen bazı görünüm mantığım olduğu özel EditorTemplates / String.ascx'imde kullanın.Verilen anonim nesne EditorFor(), çağrılan bir parametredir additionalViewDatave özellikleri ViewDataToplamak.


19
Cidden, hala MVC3'te bu sınırlamanın bir anlamı yok ve gerçekten can sıkıcı. Dünyanın her yerinden insanlar bu saçmalıkla vakit geçiriyor ve saçlarını çekiyor. Bunu Microsoft Connect'e gönderiyorum.
Junior Mayhé


3
Sadece ben miyim, yoksa çok basit olması gereken bir şey için çok fazla bs gibi mi görünüyor?
Eric K

Belki bu size yardımcı olabilir: [CSS sınıfları ve HTML öznitelikleri ile EditorFor-Implementation] [1] [1]: stackoverflow.com/questions/12675708/…
FunThom

Yanıtlar:


96

EditorFormeta verilerle çalışır, bu nedenle html nitelikleri eklemek istiyorsanız bunu her zaman yapabilirsiniz . Diğer bir seçenek de özel bir şablon yazmak ve kullanmaktır TextBoxFor:

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

Html öznitelikleri modeldeki diğer özelliklere bağlı olarak değiştiğinden meta veriler çalışmaz, başka bir deyişle etki alanı veya viemodel mantığı, statik meta verileri değil html özniteliklerini belirlemelidir. Ya da noktayı kaçırıyor muyum, meta verileri dinamik olarak ayarlayabilir miyim?
Typo Johnson

Nedir PeriodType? Bu basit bir özellik değil mi? Karmaşık bir nesne ise, özelliğin tür adının ~/Views/ControllerName/EditorTemplates/SomeType.ascxolduğu yere bir kısmi yerleştirerek tüm şablonu özelleştirebilirsiniz . SomeTypePeriodType
Darin Dimitrov

Ayrıca önerilen kodunuz, tüm modeli belirli bir özelliğe erişen kısmi bir şablona geçirmek anlamına gelir; bu, her özellik için bir kısmım olduğu anlamına mı gelir?
Typo Johnson

2
Şimdi anlıyorum seni <% = Html.EditorFor (model => model.Control.PeriodEndDate, new {Modifiable = model.Control.PeriodEndDateModifiable})%> ve özel EditorTemplates / String.ascx'imde ViewData ["PeriodEndDateModifiable"] kullanabilirim. Teşekkürler
Typo Johnson

1
@ JuniorMayhé, buna sıkıcı bir sınırlama demezdim. Daha dikkatli düşünürseniz bunun mantıklı olduğunu anlayacaksınız. Aslında EditorFor yardımcısının tüm amacı, karşılık gelen bir şablona sahip olabilmenizdir. Bu şablon herhangi bir işaret içerebilir. Mutlaka tek bir unsur değil. @classÖrneğin, 3 div içeren bir düzenleyici şablonu tanımlamak kesinlikle mantıklı olmaz . Html.TextBoxFor yardımcısı, bu yardımcının ne ürettiğini bildiğiniz için bunu tanımlamanıza olanak tanır - bir metin kutusu, bu nedenle bir giriş öğesine bir sınıf tanımlamak anlamlıdır.
Darin Dimitrov

115

MVC 5.1 güncellemesi artık aşağıdaki yaklaşımı doğrudan destekliyor, bu nedenle yerleşik düzenleyici için de çalışıyor. http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (Bu ya bir Büyük zihin durumu aynıdır ya da cevabımı okurlar :)

Güncellemeyi Sonlandır

Kendi düzenleyici şablonunuzu veya artık yerleşik editörler için aşağıdaki yaklaşımı doğrudan destekleyen MVC 5.1 ile kullanıyorsanız.

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

sonra şablonunuzda (MVC 5.1'deki basit türler için gerekli değildir)

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

5
Bu yeni özellik, dört yıl önce sorulan orijinal sorunu mükemmel bir şekilde çözüyor.
CoderSteve

1
TextBoxFor ve bunun gibi yardımcılar yerine tonlarca özel düzenleyici şablonu kullanırsam, her birine ViewData [...] eklemenin harika bir fikir olduğunu söyleyemem ... :(
Alexander,

42

MVC 5.1'den itibaren, artık şunları yapabilirsiniz:

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

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


Yukarıdaki bağlantı öldü. Bu MVC 5.1'de mevcuttur, daha fazla bilgiyi burada bulabilirsiniz: asp.net/mvc/overview/releases/mvc51-release-notes#new-features
Alaa Masoud

1
Teşekkürler, bağlantıyı da düzelttim.
vtforester

2
htmlAttributes nasıl birleştirilir?
Bart Calixto

Bu yalnızca yerleşik / varsayılan EditorForşablonlarla çalışır. Kendinizinkini uygularsanız, AntonK'nin cevabına uymanız gerekir.
mxmissile

6

Şimdi ASP.Net MVC 5.1 , bunun için yerleşik bir desteğe sahip.

Sürüm Notlarından

Artık EditorFor'da HTML niteliklerinin anonim bir nesne olarak aktarılmasına izin veriyoruz.

Örneğin:

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

4

İşte VB.Net kod sözdizimi html MVC 5.1 öznitelikleri EditorFor

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

3

Neden sadece kullanmıyorsun

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

30
Bunun bir nedeni, DisplayFor'un bir girdi oluşturmaması, dolayısıyla değerin geri göndermede kaybolmasıdır.
ProfK

2
Diğer bir neden, düzenleyicinin şu anda kilitli olduğu ancak her zaman kilitli olmadığı ve verilerin potansiyel olarak düzenlenebilir olduğunu bildirmek istediğiniz özel senaryodur - sadece şimdi değil.
Mir

2

Meta Verileri kullanmak istemiyorsanız [UIHint("PeriodType")], özelliği dekore etmek için bir öznitelik kullanabilirsiniz veya karmaşık bir türse hiçbir şeyi dekore etmeniz gerekmez. EditorFor daha sonra EditorTemplates klasöründe bir PeriodType.aspx veya ascx dosyası arayacak ve bunun yerine onu kullanacaktır.


Teşekkürler, editör şablonumdaki if / else yalnızca belirli alanlar için gerekliyse, bunu yapabilirim
Typo Johnson

Modeli değiştiremeyeceğinizi (kodunuzu değiştiremeyeceğinizi) söylemenize rağmen, UIHint ile doğrudan dekorasyon yapmak bir seçenek olmayacaktır.
Darrel Lee

2

Nullable bool'a bağlanan bir onay kutusu için bugün aynı sorunla boğuşuyordum ve modelimi değiştiremediğim için (kodumu değil) bunu halletmek için daha iyi bir yol bulmalıydım. Biraz kaba kuvvet ama karşılaşabileceğim vakaların% 99'unda işe yaramalı. Açıkçası, her giriş türü için geçerli özniteliklerin bazı manuel popülasyonunu yapmanız gerekir, ancak sanırım hepsini onay kutusu için aldım.

Boolean.cshtml düzenleyici şablonumda:

@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)

Ben eklendi Dictionary<string,string> attribs = new Dictionary<string,string>();ve attribs.Add("tabindex","16");bunlardan birinde @( )benim sayfanın üst kısmındaki blokların. Sonra @Html.CheckBox("IsActive", Model.IsActive.HasValue ? Model.IsActive : false, attribs)sayfamda yaptım ve bana bir hata veriyor: "'System.Web.Mvc.HtmlHelper <MyProject.Models.MyObject>' 'CheckBox' ve en iyi uzantı yöntemi aşırı yüklemesi 'System.Web. Mvc.InputExtensions.CheckBox (System.Web.Mvc.HtmlHelper, string.bool, object) 'bazı geçersiz bağımsız değişkenler içeriyor ".
vapcguy

2

Yine de EditorFor'u kullanabilirsiniz. Sadece style / html niteliğini ViewData olarak iletin.

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

EditorFor, işlemek için şablonlar kullandığından, mülkünüz için varsayılan şablonu geçersiz kılabilir ve stil niteliğini ViewData olarak iletebilirsiniz.

Dolayısıyla, EditorTemplate'iniz aşağıdakileri istiyor:

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

bunun gibi kullanabilirsiniz; ile aynı çıktı Html.EditorForve html niteliklerinizi ekleyebilirsiniz


Uygulamaya çalıştığınız TextBoxForher türden DisplayFormatşeyi göz ardı etmesi dışında .
Eric K

1

Views / Shared / EditorTemplates / MyTypeEditor.vbhtml'deki tür için kendi şablonunuzu oluşturmanız yeterlidir.

@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 özelliğiyle görünümünüzden düzenleyiciyi çağırın:

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

VB sözdizimini bağışlayın. Biz böyle yuvarlanıyoruz.


1

Benim durumumda, ek öznitelikler alabilen bir HTML5 sayı giriş düzenleyici şablonu oluşturmaya çalışıyordum. Daha düzgün bir yaklaşım kendi HTML Helper'ınızı yazmak olacaktır, ancak .ascx şablonuma zaten sahip olduğum için şu yaklaşımı kullandım:

<%@ 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])%>
       <% }
   } %> />

Bu çirkin bit, bir sayı türü girişi oluşturur ve "özniteliklere" sahip bir ViewData Sözlüğü arar. Anahtar / değer çiftlerini öznitelikler olarak ekleyerek sözlükte yinelenecektir. ID özniteliğindeki Regex ilgisizdir ve bir koleksiyonda kullanıldığında, normalde alt çizgi olarak kaçan GetFullHtmlFieldId()köşeli parantez içeren bir id döndürdüğü için vardır [].

Bu şablon daha sonra şu şekilde adlandırılır:

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

Ayrıntılı, ama işe yarıyor. Özellik adlarını sözlük kullanmak yerine özellik adları olarak kullanmak için muhtemelen şablondaki yansımayı kullanabilirsiniz.


1

ViewDataDenetleyicide kullanarak koşulu ayarlayın

ViewData["Modifiable"] = model.recProcessed;

Ardından, denetimin html niteliğini ayarlamak için düzenleyici şablonunda bu görünüm verilerini kullanın

@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 ve üstü çözüm (yerel HtmlAttributes birleştirecek ve EditorTemplates'te tanımlanacaktır):

Paylaşılan \ EditorTemplates \ String.cshtml:

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

Uzantılar:

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

Kullanımı:

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

1
Teşekkürler, işe yarıyor. Beraber _ değiştirmek zorunda tüm data_xxx nitelikler hariç - yayın yaparken source1ve source2olarak IDictionary<string, object>. Bu işlevi yaptım: private static IDictionary<string, object> ToHtmlAttributesDictionary(this IEnumerable<KeyValuePair<string, object>> dico) { return dico.ToDictionary(s => s.Key.Replace('_', '-'), s => s.Value); }
Marien Monnier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.