2012-08-30 25 views
12

Normalmente renderizo mis formularios por @ Html.RenderModel, pero esta vez tengo una lógica de renderizado compleja y la renderizo manualmente. Decidí crear una plantilla de editor para una propiedad. Aquí está el código (copiar pegar de aplicación editor de plantillas de objeto por defecto):Plantilla de editor de ASP.NET MVC para la propiedad

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
<% var modelMetadata = ViewData.ModelMetadata; %> 
<% if (modelMetadata.HideSurroundingHtml) { %> 
    <%= Html.Editor(modelMetadata.PropertyName) %> 
<% } else { %> 
    <% if (!String.IsNullOrEmpty(Html.Label(modelMetadata.PropertyName).ToHtmlString())) { %> 
     <div class="editor-label"><%= Html.Label(modelMetadata.PropertyName) %></div> 
    <% } %> 
    <div class="editor-field"> 
     <%= Html.Editor(modelMetadata.PropertyName) %> 
     <%= Html.ValidationMessage(modelMetadata.PropertyName) %> 
    </div> 
<% } %> 

Y aquí es cómo lo uso:

@Html.EditorFor(x => x.SomeProperty, "Property") //"Property" is template above 

Pero no funcionó: las etiquetas se representan, independientemente de DisplayName y los editores no se representan en absoluto (en Watches Html.Editor (modelMetadata.PropertyName muestra una cadena vacía). ¿Qué estoy haciendo mal?

Respuesta

0

¿Qué tipo es "x.SomeProperty"? Voy a suponer que por ahora es tipo se llama Propiedad.

MyModel.cs

public class MyModel 
{ 
    public Property SomeProperty { get; set; } 
} 

Property.cs

public class Property 
{ 
    [Display(Name="Foo")] 
    public int Value { get; set; } 
} 

Vistas/Shared/EditorTemplates/Property.cshtml

@model MvcApplication1.Models.Property 

@Html.LabelFor(model => model.Value) 
@Html.EditorFor(model => model.Value) 
@Html.ValidationMessageFor(model => model.Value) 

MyView.cshtml

@Html.EditorFor(model=>model.SomeProperty) 

Si no proporciona templatename para EditorFor helper encuentra editortemplate cuyo nombre coincide con SomeProperty's tipo.

Actualización:

Para realizar una editortemplate personalizado para la cadena que hace:

Modelo

public class MyModel 
{ 
    public string SomeProperty { get; set; } 
} 

Vista:

@Html.EditorFor(model => model.SomeProperty,"Property") 

O, alternativamente:

Modelo:

public class MyModel 
{ 
    [DataType("Property")] 
    public string SomeProperty { get; set; } 
} 

Vista:

@Html.EditorFor(model => model.SomeProperty) 

Vistas/Shared/EditorTemplates/Property.cshtml:

@model string 

@Html.Raw("I'm using property editortemplate:") 
@Html.Label(ViewData.ModelMetadata.PropertyName) 
@Html.Editor(ViewData.ModelMetadata.PropertyName) 
@Html.ValidationMessage(ViewData.ModelMetadata.PropertyName) 
+0

El tipo de SomeProperty es cadena, por lo que espero que el cuadro de texto se represente – SiberianGuy

+0

Ver la respuesta actualizada –

+0

No necesito plantilla para cadena, necesito una plantilla general para cualquier propiedad – SiberianGuy

12

que está llamando editor de su editor. Como @RPM1984 reformula @ darin-dmitrov en comentario en this respuesta: Solo puede tener 1 plantilla utilizada en tiempo de ejecución para un tipo determinado, en un contexto particular de Vistas determinado.

Si cambia su punto de vista para hacer cuadro de texto en lugar de editor, funciona, he intentado:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
<% var modelMetadata = ViewData.ModelMetadata; %> 
<% if (modelMetadata.HideSurroundingHtml) 
    { %> 
    <%= Html.Editor(modelMetadata.PropertyName) %> 
<% } 
    else 
    { %> 
    <% if (!String.IsNullOrEmpty(modelMetadata.DisplayName)) 
     { %> 
     <div class="editor-label"><%= Html.Label(modelMetadata.PropertyName) %></div> 
    <% } %> 
    <div class="editor-field"><%= Html.TextBox(modelMetadata.PropertyName) %> <%= Html.ValidationMessage(modelMetadata.PropertyName) %></div> 
<% } %> 

Si desea hacer alguna otra cosa en lugar de cuadro de texto (es decir desplegable lista), es necesario decidir eso dentro de tu plantilla para esa propiedad y renderízalo. O bien, si tiene algo común para más editores, por lo general extraer que en vista parcial en la carpeta compartida, y sólo tiene que utilizar Html.Partial("ViewName")

Y, en cuanto a etiquetas se representan, independientemente de DisplayName, para evitar la etiqueta de la prestación si hay sin nombre para mostrar, cambiar su condición a si !String.IsNullOrEmpty(modelMetadata.DisplayName) (ya poner esa manera en el bloque de código principal)

EDITAR Esta edición se refiere a la segunda cuestión relacionada con object.ascx editor de plantillas por defecto. Este es el código de object.ascx, tomada de Brad Wilson's blog:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %> 
    <%= ViewData.ModelMetadata.SimpleDisplayText%> 
<% } 
    else { %>  
    <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit 
         && !ViewData.TemplateInfo.Visited(pm))) { %> 
     <% if (prop.HideSurroundingHtml) { %> 
      <%= Html.Editor(prop.PropertyName) %> 
     <% } 
      else { %> 
      <% if (!String.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())) { %> 
       <div class="editor-label"><%= Html.Label(prop.PropertyName) %></div> 
      <% } %> 
      <div class="editor-field"> 
       <%= Html.Editor(prop.PropertyName) %> 
       <%= Html.ValidationMessage(prop.PropertyName, "*") %> 
      </div> 
     <% } %> 
    <% } %> 
<% } %> 

Este código llama de hecho Html.Editor desde el interior del editor, pero dentro de un bucle que crea lista de editores de propiedades de modelo complejo. Cada una de estas llamadas invocará el editor correspondiente (es decir, para la cadena mostrará string.ascx allí, etc.), y solo si tiene alguna propiedad "desconocida" que no es una cadena y no hay un editor específico para ella (es decir, byte []) se invocará object.ascx por ella, pero esto es NO llamando al editor de la propiedad actual (lo que está tratando de hacer):

la responsabilidad principal del modelo de objetos está mostrando todas las propiedades de un objeto complejo, junto con etiquetas para cada propiedad. Sin embargo, también es responsable de mostrar el valor del NullDisplayText del modelo si es nulo, y también es responsable de garantizar que solo muestre un nivel de propiedades (también conocido como "inmersión superficial" de un objeto). En la próxima publicación del blog, hablaremos sobre formas de personalizar esta plantilla, incluida la realización de operaciones de "inmersión profunda".


RESUMEN

versión corta:

Más editores para misma propiedad es básicamente la solución de las diferencias funcionales ("por si/no me quieren aquí grupo de radio y no desplegable) ", y para las diferencias visuales deben usarse vistas parciales, ya que puede anidarlas tanto como desee, ya que las llama explícitamente por nombre para que no se impongan límites, usted es responsable de evitar cualquier posible recursión.

Versión larga:

he estado investigando esto, ya que tengo el mismo problema, estoy usando editor de plantillas para hacer <li> o <td> elemento (dependiendo de la configuración/tema) y desde su interior llamar a otro editor que contiene etiqueta e entrada (lo mismo para ambos casos, pero si la propiedad es bool, la entrada es antes de la etiqueta), donde vuelvo a llamar a la tercera plantilla (para evitar la duplicación de código para la etiqueta/entrada y los escenarios de entrada/etiqueta), pero esto no funciona. Aunque no encontré ninguna explicación sobre msdn u otra fuente relevante, descubrí que el único escenario en el que el editor no da nada es cuando quieres renderizar el editor para la propiedad que es el contexto del editor actual (por lo que en realidad es exactamente lo que yo ya citado: "Solo se puede usar 1 plantilla en tiempo de ejecución para un tipo dado, en un contexto particular de Vistas determinado").Después de pensar un poco más sobre esto, ahora creo que tienen razón al imponer este límite, ya que la propiedad x solo se puede representar con un editor. Puede tener tantos editores para la propiedad x como desee, pero no puede representar una propiedad una sola vez utilizando más de una plantilla. Cualquiera de sus plantillas para representar la propiedad x puede usar otras plantillas para representar PIEZAS de la propiedad x, pero no puede usar (igual o diferente) editor para x más de una vez (se aplica la misma lógica que tener dos o más propiedades x (mismo tipo) y nombre) en el mismo modelo).

Además, si se pudiera insertar otra plantilla para la propiedad actual en la plantilla actual, que permite el encadenamiento de cualquier número de plantillas para la propiedad actual, y puede causar fácilmente la recursividad, por lo que de una manera u otra que le llevará a stackoverflow:)

+0

Sí, estoy llamando al editor desde un editor, pero es lo mismo que sucede cuando utiliza RenderModel con la plantilla del editor de objetos predeterminado. Y funciona para la plantilla del editor de objetos. Entonces, ¿cómo se diferencia mi código de eso? – SiberianGuy

+1

¿se refiere a las plantillas predeterminadas de http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html? Hay una diferencia, prop.PropertyName se usa para llamar al editor para propiedades de modelos complejos, para el modelo en sí se usa <% = ViewData.ModelMetadata.SimpleDisplayText%>. Recuerde que para todas las propiedades se llamará a su editor predeterminado, por lo tanto, cadena para propiedad de cadena, etc., de modo que si no hay un editor "específico", invocará el objeto con texto de visualización, porque ese objeto "desconocido" no puede editarse. –

+0

Tienes razón, el problema es que tengo un tipo de recursión aquí. Pero en realidad no veo ningún motivo por el que ASP.NET MVC no pueda resolverlo. – SiberianGuy

Cuestiones relacionadas