Właściwości EditorFor () i html


113

Wersje zapoznawcze Asp.Net MVC 2.0 zapewniają pomocników, takich jak

Html.EditorFor(c => c.propertyname)

Jeśli nazwa właściwości to łańcuch, powyższy kod renderuje pole tekstowe.

Co zrobić, jeśli chcę przekazać właściwości MaxLength i Size do pola tekstowego lub własnej właściwości klasy CSS?

Czy muszę utworzyć jeden szablon dla każdej kombinacji rozmiaru i długości w mojej aplikacji? Jeśli tak, to nie czyni domyślnych szablonów użytecznymi.

Odpowiedzi:


92

W MVC3 możesz ustawić szerokość w następujący sposób:

@Html.TextBoxFor(c => c.PropertyName, new { style = "width: 500px;" })

62
@vondip. Upewnij się, że to TEXTBOX, a nie EDYTOR. Doenst współpracuje z redaktorem.
Kasper Skov

1
Działa również z obszarami tekstowymi: @ Html.TextAreaFor (c => c.PropertyName, new {style = "width: 500px;"})
Tarzan,

Zwróć uwagę, że niektóre adnotacje danych nie są obsługiwane przez TextBoxFor, który działałby z EditorFor, na przykład FormatString
AaronLS

14
Czy to nie odpowiada, całkowicie ignoruje to, o co chodzi, a mianowicie o funkcjonalność EditorFor-Template?
Philipp M,

1
Korzystanie z TextBoxFor wyłącza jednak formaty wyświetlania ustawione jako adnotacje danych
Anders Lindén

61

Rozwiązałem to, tworząc EditorTemplate o nazwie String.ascx w moim folderze / Views / Shared / EditorTemplates:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<% int size = 10;
   int maxLength = 100;
   if (ViewData["size"] != null)
   {
       size = (int)ViewData["size"];
   }
   if (ViewData["maxLength"] != null)
   {
       maxLength = (int)ViewData["maxLength"];
   }
%>
<%= Html.TextBox("", Model, new { Size=size, MaxLength=maxLength }) %>

Moim zdaniem używam

<%= Html.EditorFor(model => model.SomeStringToBeEdited, new { size = 15, maxLength = 10 }) %>

U mnie działa jak urok!


1
genialne - miałem listę rozwijaną DateTime, którą już stworzyłem, ale przekazywanie do niej dodatkowych atrybutów okazało się bolesne - to rozwiązało problem, dzięki!
Terry_Brown

EditorFor z maxlength nie działa dla mnie (TextBoxFor z drugiej strony)
Drejc

@tjeerdhans, użyłem tego kodu, aby dostosować mój css. Działa, ale niestety zastępuje oryginalne wartości css. Jak mogę zamiast tego dołączyć go do oryginalnego pliku CSS?
Rosdi Kasim

33

Żadna z odpowiedzi w tym lub innym wątku na temat ustawiania atrybutów HTML dla @ Html.EditorFor nie była dla mnie zbyt pomocna. Jednak znalazłem świetną odpowiedź pod adresem

Stylizowanie pomocnika @ Html.EditorFor

Użyłem tego samego podejścia i działało pięknie bez pisania dużej ilości dodatkowego kodu. Zwróć uwagę, że atrybut id wyniku html Html.EditorFor jest ustawiony. Kod widoku

<style type="text/css">
#dob
{
   width:6em;
}
</style>

@using (Html.BeginForm())
{
   Enter date: 
   @Html.EditorFor(m => m.DateOfBirth, null, "dob", null)
}

Właściwość modelu z adnotacją do danych i formatowaniem daty jako „dd MMM rrrr”

[Required(ErrorMessage= "Date of birth is required")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MMM yyyy}")]
public DateTime DateOfBirth { get; set; }

Działał jak urok bez pisania mnóstwa dodatkowego kodu. Ta odpowiedź używa ASP.NET MVC 3 Razor C #.


1
U mnie też działało bardzo dobrze w MVC4.
atconway

1
Formatowanie zadziałało, ale teraz zwracana jest wartość null dla danych skutecznie wyłączając pudełko.
Joe

2
Nie wiem, co to jest z ludźmi z MVC, to tak, jakby nikt nie napisał każdej strony internetowej, która obsługuje wiele języków i formatów liczb.
adudley,

Bardzo dobrze. To proste, działa i faktycznie odpowiada na pytanie PO, zamiast oferować alternatywy. Korzystanie z MVC4.
draconis

Ostrzeżenie: wydaje się, że DateTime jest renderowane jako type = "datetime", co jest błędne w przypadku daty urodzenia, a niektóre przeglądarki (np. Firefox mobile) właściwie obsługują ten typ danych wejściowych, w tym składnik czasu, który prawdopodobnie nie przejdzie weryfikacji i jest trudny lub niemożliwe do usunięcia przez użytkownika.
brianary

25

Może chcieć przyjrzeć się postowi na blogu Kirana Chanda , używa on niestandardowych metadanych w modelu widoku, takich jak:

[HtmlProperties(Size = 5, MaxLength = 10)]
public string Title { get; set; }

Jest to połączone z niestandardowymi szablonami, które wykorzystują metadane. Moim zdaniem czyste i proste podejście, ale chciałbym zobaczyć ten typowy przypadek użycia wbudowany w mvc.


71
Żartujesz? To zbyt duża przesada jak na tak prostą rzecz. Coraz częściej wracam do czystego HTML i zapominam o metodach pomocniczych MVC. 5 minut temu miałem prosty TextboxFor, który z powodzeniem uruchomił datepicker jquery. Teraz tylko dlatego, że chciałem zmienić sposób, w jaki formatuje wstępnie załadowaną wartość daty, musiałem zmienić ją na EditorFor. Ale teraz nagle nie mogę już określić własnych atrybutów HTML bez pisania tych nadmiernie rozdętych niestandardowych metod rozszerzeń i pomocników. Co za żart. Musi być prostszy sposób, wy szaleni profesorowie nie wiecie, kiedy przestać.
Aaron

1
Myślę, że mieszasz konteksty. Jak możesz mieć dwa różne wywołania EditorFor, z których każde uzyskuje własne wartości rozmiaru i maksymalnej długości za pomocą podanego linku? Jeśli nie chcesz używać EditorFor, zawsze możesz użyć pomocnika TextBox lub prostego html. Ale to nie jest pytanie!
chandmk

@Aaron od najnowszego MVC, możesz określić dodatkowe atrybuty html EditorFor, przekazując je jako:new { htmlAttributes: { @class = "yourclass" } }
JoeBrockhaus

17

Dziwię się, że nikt nie wspomniał o przekazaniu go w „additionalViewData” i przeczytaniu po drugiej stronie.

Widok (z podziałami linii, dla większej przejrzystości):

<%= Html.EditorFor(c => c.propertyname, new
    {
        htmlAttributes = new
        {
            @class = "myClass"
        }
    }
)%>

Szablon edytora:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>

<%= Html.TextBox("", Model, ViewData["htmlAttributes"])) %>

Na tej podstawie stworzyłem pomocnika, który bierze pod uwagę łączenie atrybutów - stackoverflow.com/a/11498094/79842
Colin Bowern

6

Problem polega na tym, że twój szablon może zawierać kilka elementów HTML, więc MVC nie będzie wiedział, do którego z nich zastosować twój rozmiar / klasę. Będziesz musiał sam to zdefiniować.

Utwórz szablon jako pochodzenie z własnej klasy o nazwie TextBoxViewModel:

public class TextBoxViewModel
{
  public string Value { get; set; }
  IDictionary<string, object> moreAttributes;
  public TextBoxViewModel(string value, IDictionary<string, object> moreAttributes)
  {
    // set class properties here
  }
  public string GetAttributesString()
  {
     return string.Join(" ", moreAttributes.Select(x => x.Key + "='" + x.Value + "'").ToArray()); // don't forget to encode
  }

}

W szablonie możesz to zrobić:

<input value="<%= Model.Value %>" <%= Model.GetAttributesString() %> />

Twoim zdaniem robisz:

<%= Html.EditorFor(x => x.StringValue) %>
or
<%= Html.EditorFor(x => new TextBoxViewModel(x.StringValue, new IDictionary<string, object> { {'class', 'myclass'}, {'size', 15}}) %>

Pierwsza forma wyrenderuje domyślny szablon dla łańcucha. Drugi formularz wyrenderuje szablon niestandardowy.

Alternatywna składnia używa płynnego interfejsu:

public class TextBoxViewModel
{
  public string Value { get; set; }
  IDictionary<string, object> moreAttributes;
  public TextBoxViewModel(string value, IDictionary<string, object> moreAttributes)
  {
    // set class properties here
    moreAttributes = new Dictionary<string, object>();
  }

  public TextBoxViewModel Attr(string name, object value)
  {
     moreAttributes[name] = value;
     return this;
  }

}

   // and in the view
   <%= Html.EditorFor(x => new TextBoxViewModel(x.StringValue).Attr("class", "myclass").Attr("size", 15) %>

Zauważ, że zamiast robić to w widoku, możesz to również zrobić w kontrolerze lub znacznie lepiej w ViewModel:

public ActionResult Action()
{
  // now you can Html.EditorFor(x => x.StringValue) and it will pick attributes
  return View(new { StringValue = new TextBoxViewModel(x.StringValue).Attr("class", "myclass").Attr("size", 15) });
}

Zauważ również, że możesz utworzyć podstawową klasę TemplateViewModel - wspólną podstawę dla wszystkich szablonów widoków - która będzie zawierała podstawowe wsparcie dla atrybutów / itp.

Ale ogólnie myślę, że MVC v2 potrzebuje lepszego rozwiązania. To wciąż Beta - idź o to zapytaj ;-)


Myślę, że lepszym sposobem radzenia sobie z tym jest, jak wspomniałem tutaj stackoverflow.com/questions/1647609/ ... Krótko mówiąc, robienie czegoś podobnego do sposobu, w jaki WPF radzi sobie z problemem ... Elementy dowolnych stylów (w tym przypadku włączone atrybuty) są przekazywane do szablonu, a szablon decyduje, do którego elementu wewnętrznego zastosuje styl ...
vdhant

6

Myślę, że najlepszym rozwiązaniem jest użycie CSS. Chciałbym móc zrobić więcej z kodowaniem .NET, jak w XAML, ale CSS w przeglądarce jest królem.

Site.css

#account-note-input { 
  width:1000px; 
  height:100px; 
} 

.cshtml

<div class="editor-label"> 
  @Html.LabelFor(model => model.Note) 
</div> 
<div class="editor-field"> 
  @Html.EditorFor(model => model.Note, null, "account-note-input", null) 
  @Html.ValidationMessageFor(model => model.Note) 
</div>

Joe


Działa to bardzo dobrze do wprowadzania zmian CSS specyficznych dla kontroli podczas korzystania z EditorForszablonu. Używam MVC4 i to działało świetnie.
atconway

6

Podobnie jak w MVC 5, jeśli chcesz dodać atrybuty, możesz po prostu to zrobić

 @Html.EditorFor(m => m.Name, new { htmlAttributes = new { @required = "true", @anotherAttribute = "whatever" } })

Informacje znalezione z tego bloga


3

Możesz zdefiniować atrybuty dla swoich właściwości.

[StringLength(100)]
public string Body { get; set; }

Jest to znane jako System.ComponentModel.DataAnnotations. Jeśli nie możesz znaleźć tego ValidationAttribute, czego potrzebujesz, zawsze możesz zdefiniować niestandardowe atrybuty.

Pozdrawiam, Carlos


3
Mówi o atrybutach HTML, takich jak maksymalna długość, a nie walidacja.
Mathias F

Mam nadzieję, że silnik widoku będzie również przestrzegał adnotacji DataAnnotations. Nie bawiłem się jeszcze z MVC2.
mxmissile

Wypróbowałem adnotację danych StringLength. To nie działa z EditorFor.
wayne.blackmon

3

Może to nie jest najlepsze rozwiązanie, ale jest proste. Możesz napisać rozszerzenie do klasy HtmlHelper.EditorFor. W tym rozszerzeniu można podać parametr options, który zapisze opcje do ViewData dla pomocnika. Oto kod:

Po pierwsze, metoda rozszerzenia:

public static MvcHtmlString EditorFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, TemplateOptions options)
{
    return helper.EditorFor(expression, options.TemplateName, new
    {
        cssClass = options.CssClass
    });
}

Następnie obiekt opcji:

public class TemplateOptions
{
    public string TemplateName { get; set; }
    public string CssClass { get; set; }
    // other properties for info you'd like to pass to your templates,
    // and by using an options object, you avoid method overload bloat.
}

I na koniec, oto wiersz z szablonu String.ascx:

<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = ViewData["cssClass"] ?? "" }) %>

Szczerze mówiąc, myślę, że jest to proste i jasne dla biednej duszy, która musi przestrzegać twojego kodu w przyszłości. Można go łatwo rozszerzyć o różne inne informacje, które chcesz przekazać do swoich szablonów. Jak dotąd działa dobrze w projekcie, w którym staram się zawrzeć jak najwięcej w zestawie szablonów, aby pomóc ujednolicić otaczający kod HTML, a la http://bradwilson.typepad.com/blog/2009/ 10 / aspnet-mvc-2-templates-part-5-master-page-templates.html .


3

Napisałem wpis na blogu, aby odpowiedzieć na własne pytanie

Dodawanie obsługi atrybutów html dla szablonów - ASP.Net MVC 2.0 Beta


Pomysł umieszczenia właściwości formatowania HTML w modelu (widoku) jest sprzeczny z ideą MVC, aby oddzielić widok od logiki! A co by było, gdyby model wymagał różnych reprezentacji w HTML?
saintedlama

2
@Saintedlama: To perfekcyjnie umieścić adnotacje danych na viewmodel , ponieważ ViewModel jest jedynym celem jest zapewnienie strukturalnego modelu danych dla widoku . Nie mylić z modelem , który w terminologii MVC zwykle reprezentuje jednostkę DB, która nie powinna mieć żadnych właściwości związanych z widokiem. To powiedziawszy, szkoda, że ​​jego adnotacje dotyczące modelu widoku zaczynają się od HTMLxxx, ponieważ oznacza to HTML jako warstwę prezentacji, ale gdzieś trzeba narysować linię. :) Poza tym, jeśli ponownie użyje modelu widoku dla, powiedzmy, aplikacji Silverlight, może łatwo dodać atrybuty SL do swojego modelu widoku.
Boris B.

3

Nie wiem, dlaczego to nie działa w przypadku Html.EditorFor, ale próbowałem TextBoxFor i u mnie zadziałało.

@Html.TextBoxFor(m => m.Name, new { Class = "className", Size = "40"})

... a także prace walidacyjne.


potrzebujesz@class = "className"
JoeBrockhaus

2

W mojej praktyce stwierdziłem, że najlepiej jest używać EditorTemplates z tylko jednym HtmlHelper w nim - TextBox, czyli w większości przypadków. Jeśli chcę mieć szablon dla bardziej złożonej struktury html, napiszę osobny HtmlHelper.

Biorąc pod uwagę, że możemy wstawić cały obiekt ViewData w miejsce htmlAttributes z TextBox. Ponadto możemy napisać kod dostosowujący dla niektórych właściwości ViewData, jeśli wymagają specjalnego traktowania:

@model DateTime?
@*
    1) applies class datepicker to the input;
    2) applies additionalViewData object to the attributes of the input
    3) applies property "format" to the format of the input date.
*@
@{
    if (ViewData["class"] != null) { ViewData["class"] += " datepicker"; }
    else { ViewData["class"] = " datepicker"; }
    string format = "MM/dd/yyyy";
    if (ViewData["format"] != null)
    {
        format = ViewData["format"].ToString();
        ViewData.Remove("format");
    }
}

@Html.TextBox("", (Model.HasValue ? Model.Value.ToString(format) : string.Empty), ViewData)

Poniżej znajdują się przykłady składni w widoku i wyjściowy kod HTML:

@Html.EditorFor(m => m.Date)
<input class="datepicker" data-val="true" data-val-required="&amp;#39;Date&amp;#39; must not be empty." id="Date" name="Date" type="text" value="01/08/2012">
@Html.EditorFor(m => m.Date, new { @class = "myClass", @format = "M/dd" })
<input class="myClass datepicker" data-val="true" data-val-required="&amp;#39;Date&amp;#39; must not be empty." id="Date" name="Date" type="text" value="1/08">

2

Ponieważ pytanie dotyczy sugestii EditorFor not TextBoxFor WEFX, nie działa.

Aby zmienić poszczególne pola wejściowe, możesz przetworzyć dane wyjściowe metody EditorFor:

<%: new HtmlString(Html.EditorFor(m=>m.propertyname).ToString().Replace("class=\"text-box single-line\"", "class=\"text-box single-line my500pxWideClass\"")) %>

Możliwa jest również zmiana WSZYSTKICH Twoich EditorFors, jak się okazuje MVC ustawia klasę pól tekstowych EditorFor z .text-box , dlatego możesz po prostu nadpisać ten styl w swoim arkuszu stylów lub na stronie.

.text-box {
    width: 80em;
}

Dodatkowo możesz ustawić styl dla

input[type="text"] {
    width: 200px;
}
  • to nadpisuje .text-box i zmieni wszystkie wejściowe pola tekstowe, EditorFor lub inne.

Nie wszystkie pola tekstowe EditorFor () mają wartość input type = "text". Wydaje się, że właściwości DateTime są renderowane jako type = "datetime".
brianary

2

Miałem również problem z ustawieniem szerokości TextBox w MVC3, podczas gdy ustawienie atrybutu Clsss działało dla kontrolki TextArea, ale nie dla kontrolki TextBoxFor lub EditorFor:

Próbowałem śledzić i to zadziałało dla mnie:

@ Html.TextBoxFor (model => model.Title, new {Class = "textBox", style = "width: 90%;"})

również w tym przypadku Walidacje działają doskonale.


2

Jednym ze sposobów obejścia tego problemu jest posiadanie delegatów na modelu widoku do obsługi drukowania specjalnego renderowania, takiego jak ten. Zrobiłem to dla klasy stronicowania, ujawniam publiczną właściwość modelu, Func<int, string> RenderUrlaby sobie z tym poradzić.

Zdefiniuj więc, jak zostanie zapisany niestandardowy bit:

Model.Paging.RenderUrl = (page) => { return string.Concat(@"/foo/", page); };

Wyświetl widok dla Pagingklasy:

@Html.DisplayFor(m => m.Paging)

... a dla aktualnego Pagingwidoku:

@model Paging
@if (Model.Pages > 1)
{
    <ul class="paging">
    @for (int page = 1; page <= Model.Pages; page++)
    {
        <li><a href="@Model.RenderUrl(page)">@page</a></li>
    }
    </ul>
}

Może to być postrzegane jako zbyt skomplikowane sprawy, ale używam tych pagerów wszędzie i nie mogłem znieść widoku tego samego standardowego kodu, aby je renderować.


1

UPDATE: hm, oczywiście to nie zadziała, ponieważ model jest przekazywany przez wartość, więc atrybuty nie są zachowywane; ale zostawiam tę odpowiedź jako pomysł.

Myślę, że innym rozwiązaniem byłoby dodanie własnych pomocników TextBox / etc, które sprawdzą twoje własne atrybuty w modelu.

public class ViewModel
{
  [MyAddAttribute("class", "myclass")]
  public string StringValue { get; set; }
}

public class MyExtensions
{
  public static IDictionary<string, object> GetMyAttributes(object model)
  {
     // kind of prototype code...
     return model.GetType().GetCustomAttributes(typeof(MyAddAttribute)).OfType<MyAddAttribute>().ToDictionary(
          x => x.Name, x => x.Value);
  }
}

<!-- in the template -->
<%= Html.TextBox("Name", Model, MyExtensions.GetMyAttributes(Model)) %>

Ten jest łatwiejszy, ale nie tak wygodny / elastyczny.



0

Bardzo podobała mi się odpowiedź @tjeerdans, która wykorzystuje EditorTemplate o nazwie String.ascx w folderze / Views / Shared / EditorTemplates. Wydaje się, że jest to najprostsza odpowiedź na to pytanie. Jednak chciałem mieć szablon używający składni Razor. Ponadto wydaje się, że MVC3 używa szablonu String jako domyślnego (patrz pytanie StackOverflow „ Szablon wyświetlania mvc dla łańcuchów jest używany dla liczb całkowitych ”), więc musisz ustawić model na obiekt, a nie na łańcuch. Wygląda na to, że mój szablon do tej pory działa:

@model object 

@{  int size = 10; int maxLength = 100; }

@if (ViewData["size"] != null) {
    Int32.TryParse((string)ViewData["size"], out size); 
} 

@if (ViewData["maxLength"] != null) {
    Int32.TryParse((string)ViewData["maxLength"], out maxLength); 
}

@Html.TextBox("", Model, new { Size = size, MaxLength = maxLength})

0

Rozwiązałem to !!
W przypadku Razor składnia jest następująca:
@Html.TextAreaFor(m=>m.Address, new { style="Width:174px" })to dostosowuje szerokość obszaru tekstu do szerokości zdefiniowanej w parametrze style.
W przypadku ASPx składnia jest następująca:
<%=Html.TextAreaFor(m => m.Description, new { cols = "20", rows = "15", style="Width:174px" })%>
to załatwi sprawę

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.