EditorFor () e propriedades html

113

As compilações de visualização do Asp.Net MVC 2.0 fornecem ajudantes como

Html.EditorFor(c => c.propertyname)

Se o nome da propriedade for string, o código acima renderiza um texbox.

E se eu quiser passar as propriedades MaxLength e Size para a caixa de texto ou minha própria propriedade de classe css?

Preciso criar um modelo para cada combinação de tamanho e comprimento em meu aplicativo? Nesse caso, isso não torna os modelos padrão tão utilizáveis.

Chandmk
fonte

Respostas:

92

Em MVC3, você pode definir a largura da seguinte forma:

@Html.TextBoxFor(c => c.PropertyName, new { style = "width: 500px;" })
WEFX
fonte
62
@vondip. Certifique-se de que é uma CAIXA DE TEXTO e não um EDITOR. Não trabalhe com o editor.
Kasper Skov
1
Também funciona com textareas: @ Html.TextAreaFor (c => c.PropertyName, new {style = "width: 500px;"})
Tarzan
Observe que algumas anotações de dados não são suportadas pelo TextBoxFor, que funcionaria com EditorFor, como FormatString
AaronLS
14
Esta resposta não ignora totalmente o que a pergunta é, ou seja, a funcionalidade EditorFor-Template?
Philipp M
1
Usar TextBoxFor, entretanto, desativa os formatos de exibição que são definidos como anotações de dados
Anders Lindén
61

Resolvi isso criando um EditorTemplate chamado String.ascx na minha pasta / 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 }) %>

Na minha opinião, eu uso

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

Funciona como um encanto para mim!

tjeerdhans
fonte
1
brilhante - eu tinha um droppicker DateTime que eu já tinha modelado, mas passar atributos extras para ele estava sendo doloroso - isso resolveu para mim, obrigado!
Terry_Brown,
EditorFor com maxlength não funciona para mim (TextBoxFor por outro, sim)
Drejc
@tjeerdhans, usei esse código para customizar meu css. Funciona, mas infelizmente substitui os valores css originais. Como posso fazer com que seja anexado ao css original?
Rosdi Kasim
33

Nenhuma das respostas neste ou em qualquer outro tópico sobre configuração de atributos HTML para @ Html.EditorFor foi de muita ajuda para mim. No entanto, encontrei uma ótima resposta em

Estilizando um ajudante @ Html.EditorFor

Usei a mesma abordagem e funcionou perfeitamente sem escrever muito código extra. Observe que o atributo id da saída html de Html.EditorFor está definido. O código de visualização

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

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

A propriedade do modelo com anotação de dados e formatação de data como "dd MMM aaaa"

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

Funcionou como um encanto sem escrever muito código extra. Esta resposta usa ASP.NET MVC 3 Razor C #.

wayne.blackmon
fonte
1
Funcionou muito bem para mim também em MVC4.
atconway em
1
A formatação funcionou, mas agora é retornado nulo para os dados, desativando efetivamente a caixa.
Joe
2
Não sei o que é o pessoal do MVC, é como se ninguém nunca tivesse escrito um site que funcionasse com vários idiomas e formatos de números.
adudley
Muito bom. Isso é simples, funciona e, na verdade, responde à pergunta do OP, em vez de fornecer alternativas. Usando MVC4.
draconis
Aviso: DateTimes parecem renderizar como type = "datetime", o que é errado para uma data de nascimento, e alguns navegadores (como o Firefox mobile) realmente suportam corretamente esse tipo de entrada, incluindo um componente de tempo que provavelmente não passará na validação e é difícil ou impossível para o usuário remover.
brianary
25

Talvez você queira dar uma olhada na postagem do blog de Kiran Chand , ele usa metadados personalizados no modelo de visualização, como:

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

Isso é combinado com modelos personalizados que fazem uso dos metadados. Uma abordagem limpa e simples, em minha opinião, mas gostaria de ver esse caso de uso comum integrado ao mvc.

tj.
fonte
71
Você está de brincadeira? Isso é um exagero demais para uma coisa tão simples. Cada vez mais estou voltando ao HTML puro e esquecendo os métodos auxiliares inchados do MVC. 5 minutos atrás eu tinha um TextboxFor simples que lançou com sucesso um datepicker jquery. Agora, só porque eu queria alterar a forma como ele formata o valor de data pré-carregado em, tive que alterá-lo para um EditorFor. Mas agora, de repente, não consigo mais especificar meus próprios atributos HTML sem escrever esses métodos e ajudantes de extensão personalizados excessivamente inchados. Que piada. Tem que haver um jeito mais simples, seus professores malucos não sabem quando parar.
Aaron
1
Acho que você está misturando contextos. Como você pode ter duas chamadas EditorFor diferentes com cada uma obtendo seus próprios valores de tamanho e comprimento máximo com o link fornecido? Se você não quiser usar o EditorFor, você sempre pode usar o auxiliar TextBox ou html simples. Mas essa não é a questão!
chandmk
@Aaron no MVC mais recente, você pode especificar atributos html adicionais EditorForpassando-os como:new { htmlAttributes: { @class = "yourclass" } }
JoeBrockhaus
17

Estou surpreso que ninguém mencionou transmiti-lo em "additionalViewData" e lê-lo no outro lado.

Ver (com quebras de linha, para maior clareza):

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

Modelo de editor:

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

<%= Html.TextBox("", Model, ViewData["htmlAttributes"])) %>
Ishmael Smyrnow
fonte
Com base nisso, criei um auxiliar que leva em consideração a fusão de atributos - stackoverflow.com/a/11498094/79842
Colin Bowern
6

O problema é que seu modelo pode conter vários elementos HTML, então MVC não saberá a qual deles aplicar seu tamanho / classe. Você terá que definir você mesmo.

Faça seu modelo derivar de sua própria classe chamada 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
  }

}

No modelo, você pode fazer isso:

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

Em sua opinião, você:

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

A primeira forma irá renderizar o template padrão para string. O segundo formulário irá renderizar o modelo personalizado.

A sintaxe alternativa usa interface fluente:

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

Observe que em vez de fazer isso na visualização, você também pode fazer isso no controlador, ou muito melhor no 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) });
}

Observe também que você pode fazer a classe TemplateViewModel base - um terreno comum para todos os seus modelos de visualização - que conterá suporte básico para atributos / etc.

Mas, em geral, acho que MVC v2 precisa de uma solução melhor. Ainda é Beta - vá pedir ;-)

queen3
fonte
Acho que uma maneira melhor de lidar com isso é como mencionei aqui stackoverflow.com/questions/1647609/… ... Resumindo, fazendo algo semelhante à maneira como o WPF lida com o problema ... Elementos de estilos arbitrários (on, neste caso atributos) são passados ​​para o modelo e o modelo decide a qual elemento interno ele aplicará o estilo ...
vdhant
6

Acho que usar CSS é o caminho a percorrer. Eu gostaria de poder fazer mais com a codificação .NET, como em XAML, mas no navegador CSS é rei.

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

Joe Kahl
fonte
Isso funciona muito bem para fazer alterações de CSS específicas de controle ao usar o EditorFormodelo. Estou usando MVC4 e funcionou muito bem.
atconway de
6

Como no MVC 5, se você deseja adicionar quaisquer atributos, você pode simplesmente fazer

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

Informações encontradas neste blog

Jay
fonte
3

Você pode definir atributos para suas propriedades.

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

Isso é conhecido como System.ComponentModel.DataAnnotations. Se você não consegue encontrar oValidationAttribute que precisa, sempre poderá definir atributos personalizados.

Atenciosamente, Carlos

Carlos fernandes
fonte
3
Ele fala sobre atributos Html como maxlength, não validação.
Mathias F
Eu espero que o mecanismo de exibição obedeceria as DataAnnotations também. Eu não brinquei com MVC2 ainda.
mxmissile
Tentei a anotação de dados StringLength. Não funcionou com EditorFor.
wayne.blackmon 01 de
3

Esta pode não ser a solução mais inteligente, mas é direta. Você pode escrever uma extensão para a classe HtmlHelper.EditorFor. Nessa extensão, você pode fornecer um parâmetro de opções que gravará as opções no ViewData para o auxiliar. Aqui estão alguns códigos:

Primeiro, o método de extensão:

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

A seguir, o objeto de opções:

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.
}

E, finalmente, aqui está a linha do modelo String.ascx:

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

Francamente, acho que isso é direto e claro para a pobre alma que precisa manter seu código no futuro. E é fácil estender para vários outros bits de informação que você gostaria de passar para seus modelos. Está funcionando bem até agora para mim em um projeto em que estou tentando envolver o máximo que posso em um conjunto de modelos para ajudar a padronizar o html circundante, a la http://bradwilson.typepad.com/blog/2009/ 10 / aspnet-mvc-2-templates-part-5-master-page-templates.html .

local
fonte
3

Escrevi uma entrada de blog para responder minha própria pergunta

Adicionando suporte a atributos de html para modelos - ASP.Net MVC 2.0 Beta

Chandmk
fonte
A ideia de colocar propriedades de formatação HTML no modelo (visão) vai contra a ideia do MVC de separar visão e lógica! E se o modelo precisasse de diferentes representações em HTML?
saintedlama
2
@Saintedlama: É perfeitamente normal colocar anotações de dados no viewmodel , porque o único propósito do viewmodel é fornecer um modelo de dados estruturados para a view . Não deve ser confundido com modelo , que na terminologia MVC geralmente representa uma entidade de banco de dados, que não deve ter nenhuma propriedade relacionada à visualização. Dito isso, é lamentável que suas anotações de modelo de visão comecem com HTMLxxx porque isso implica HTML como uma camada de apresentação, mas uma linha deve ser desenhada em algum lugar. :) Além disso, se ele reutilizar o viewmodel para, digamos, o aplicativo silverlight, ele pode facilmente adicionar atributos SL ao seu viewmodel.
Boris B.
3

Não sei por que não funciona para Html.EditorFor, mas tentei TextBoxFor e funcionou para mim.

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

... e também trabalhos de validação.

Piotr Czyż
fonte
você precisa@class = "className"
JoeBrockhaus
2

Na minha prática, descobri que é melhor usar EditorTemplates com apenas um HtmlHelper nele - TextBox na maioria dos casos. Se eu quiser um modelo para uma estrutura html mais complexa, vou escrever um HtmlHelper separado.

Dado que podemos colar todo o objeto ViewData no lugar de htmlAttributes do TextBox. Além disso, podemos escrever alguns códigos de personalização para algumas das propriedades do ViewData se precisarem de tratamento especial:

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

Abaixo estão os exemplos da sintaxe na visualização e no html gerado:

@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">
Dmitry Efimenko
fonte
2

Porque a questão é para EditorFor não TextBoxFor a sugestão de WEFX não funciona.

Para alterar as caixas de entrada individuais, você pode processar a saída do método EditorFor:

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

Também é possível alterar TODOS os seus EditorFors, visto que o MVC define a classe das caixas de texto EditorFor com .text-box , portanto, você pode simplesmente substituir este estilo, em sua folha de estilo ou na página.

.text-box {
    width: 80em;
}

Além disso, você pode definir o estilo para

input[type="text"] {
    width: 200px;
}
  • isto substitui. caixa de texto e mudará todas as caixas de texto de entrada, EditorFor ou outro.
Stuartdotnet
fonte
Nem todas as caixas de texto EditorFor () são input type = "text". As propriedades DateTime parecem renderizar como type = "datetime".
brianary
2

Eu também tive problemas com a configuração da largura de TextBox em MVC3, enquanto a configuração do atributo Clsss funcionou para o controle TextArea, mas não para o controle TextBoxFor ou EditorFor:

Tentei seguir e funcionou para mim:

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

também neste caso as validações estão funcionando perfeitamente.

Ashish
fonte
2

Uma maneira de contornar isso é ter delegados no modelo de visualização para lidar com a impressão de renderizações especiais como esta. Eu fiz isso para uma classe de paginação, exponho uma propriedade pública no modeloFunc<int, string> RenderUrl para lidar com isso.

Portanto, defina como o bit personalizado será escrito:

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

Envie a visualização para a Pagingclasse:

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

... e para a Pagingvisão real :

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

Isso pode ser visto como uma coisa complicada demais, mas eu uso esses pagers em todos os lugares e não suportava ver o mesmo código clichê para renderizá-los.

Phil Cooper
fonte
1

ATUALIZAÇÃO: hm, obviamente isso não funcionará porque o modelo é passado por valor para que os atributos não sejam preservados; mas deixo esta resposta como uma ideia.

Outra solução, eu acho, seria adicionar seus próprios ajudantes TextBox / etc, que verificarão seus próprios atributos no modelo.

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

Este é mais fácil, mas não tão conveniente / flexível.

queen3
fonte
0

Eu realmente gostei da resposta de @tjeerdans que utiliza o EditorTemplate chamado String.ascx na pasta / Views / Shared / EditorTemplates. Parece ser a resposta mais direta a essa pergunta. No entanto, eu queria um modelo usando a sintaxe do Razor. Além disso, parece que MVC3 usa o modelo String como padrão (consulte a questão StackOverflow "O modelo de exibição mvc para strings é usado para inteiros "), então você precisa definir o modelo para objeto em vez de string. Meu modelo parece estar funcionando até agora:

@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})
zielot
fonte
0

Eu resolvi !!
Para Razor, a sintaxe é:
@Html.TextAreaFor(m=>m.Address, new { style="Width:174px" })isto ajusta a largura da área de texto para a largura que eu defini no parâmetro de estilo.
Para ASPx, a sintaxe é:
<%=Html.TextAreaFor(m => m.Description, new { cols = "20", rows = "15", style="Width:174px" })%>
isso fará o truque

Sorangwala Abbasali
fonte