2012-09-17 21 views
5

que tienen un modelo, como a continuación:Cómo acceder a C# atributo modelo dentro EditorFor

public class CreateStockcheckJobModel 
{ 
    [Engineer(true)] 
    public EngineerModel Engineer { get; set; } 
} 

Estoy prestando la propiedad Engineer en un View<CreateStockcheckJobModel> usando Html.EditorFor(m => m.Engineer, "EngineerEditor").

¿Cómo accedo al valor en el atributo Engineer (en este caso true) desde dentro del código en mi vista parcial (EngineerEditor.ascx)?


A continuación se muestra el código editor de

<%@ Control Language="C#" Inherits="ViewUserControl<EngineerModel>" %> 
<% if (PropertyImRenderingHasAttributeWithTrueBooleanValue) // What goes here? 
    { %> 
<p>Render one thing</p> 
<% } 
    else 
    { %> 
<p>Render another thing</p> 
<% } %> 

Soy consciente de reflexión, sin embargo, estoy seguro de cómo utilizar como el atributo no se añade a la clase EngineerModel se añade a la Engineer propiedad de la clase CreateStockcheckJobModel. Si pudiera obtener el PropertyInfo que estoy procesando desde el código del editor, entonces estaría ordenado, pero no sé cómo obtener esa información. Si sigo la ruta de enumerar todas las propiedades en la clase CreateStockcheckJobModel, tendré problemas si tengo más de una propiedad EngineerModel (una podría tener el atributo True, otra podría tener False).

+0

¿Qué es lo que quiere obtener? Me parece que estás haciendo mal para lograr tu objetivo. –

+0

Básicamente se trata de hacer una lista de posibles ingenieros para elegir. Quiero que el atributo controle la lista de ingenieros disponibles. –

+0

Pensé que era una aproximación razonable, ya que parece ser lo que está haciendo el atributo 'DisplayFormat' (es decir, cambiar la forma en que se representa un control/editor en función de los datos del atributo) –

Respuesta

7

Esto podría hacerse fácilmente en ASP.NET MVC 3 y más tarde mediante la implementación de la interfaz IMetadataAware en su encargo EngineerAttribute:

public class EngineerAttribute : Attribute, IMetadataAware 
{ 
    public EngineerAttribute(bool isFoo) 
    { 
     IsFoo = isFoo; 
    } 

    public bool IsFoo { get; private set; } 

    public void OnMetadataCreated(ModelMetadata metadata) 
    { 
     metadata.AdditionalValues["IsFoo"] = IsFoo; 
    } 
} 

y luego dentro de la plantilla:

<%@ Control Language="C#" Inherits="ViewUserControl<EngineerModel>" %> 
<% 
    var isFoo = (bool)ViewData.ModelMetadata.AdditionalValues["IsFoo"]; 
%> 
<% if (isFoo) { %> 
    <p>Render one thing</p> 
<% } else { %> 
    <p>Render another thing</p> 
<% } %> 

Desafortunadamente esto la interfaz no existe en ASP.NET MVC 2.Para conseguir la misma funcionalidad que podría escribir un proveedor de metadatos personalizados:

public class MyMetadataProvider : DataAnnotationsModelMetadataProvider 
{ 
    protected override ModelMetadata CreateMetadata(
     IEnumerable<Attribute> attributes, 
     Type containerType, 
     Func<object> modelAccessor, 
     Type modelType, 
     string propertyName 
    ) 
    { 
     var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 
     var engineer = attributes.OfType<EngineerAttribute>().FirstOrDefault(); 
     if (engineer != null) 
     { 
      metadata.AdditionalValues["IsFoo"] = engineer.IsFoo; 
     } 
     return metadata; 
    } 
} 

que se registrará en su Application_Start con el fin de sustituir el nombre predeterminado:

ModelMetadataProviders.Current = new MyMetadataProvider(); 

Y ahora se podía acceder a estos metadatos en su plantilla de la misma manera que mostré anteriormente, usando ViewData.ModelMetadata.AdditionalValues["IsFoo"]. Obviamente, podría poner un objeto arbitrariamente complejo dentro de la propiedad AdditionalValues, no solo booleanos.

También puede encontrar el following article útil sobre los metadatos.

1

NOTA: A continuación hay una forma posible de hacerlo, pero usar IMetadataAware como se describe en la respuesta aceptada es una manera mucho mejor. Por lo general, es mejor evitar el reflejo si puedes.

Solo puede hacerlo a través de la reflexión. Aquí hay un good example sobre cómo hacer esto para los atributos del método.

ejemplo de código para obtener el valor de EngineerAttribute en la propiedad Engineer:

PropertyInfo pi = Model.GetType().GetProperty("Engineer"); 
EngineerAttribute a = 
    System.Attribute.GetCustomAttribute(pi, typeof(EngineerAttribute)); 

ejemplo de código para conseguir todas las propiedades que tiene el atributo [Engineer(true)]:

var t = Model.GetType(); 
var engineerProperties = 
    from p in t.GetProperties() 
    let ca = System.Attribute.GetCustomAttribute(p, typeof(EngineerAttribute)) 
    where ca != null && ca.BooleanProperty == true 
    select p; 

Y cuando usted tiene estas propiedades, se puede use una sobrecarga de EditorFor que le permita especificar datos de visualización adicionales, que luego puede usar en su subvista:

Html.EditorFor(m => m.Engineer, new { IsEngineer = isEngineer }); 
+0

Sé cómo funciona la reflexión, pero estoy tener problemas para determinar para qué propiedad obtener el atributo, ya que en el editor solo tengo el tipo 'EngineerModel', no el tipo adjunto y la propiedad (es decir, el atributo no está en' EngineerModel' en una propiedad que resulta ser un 'EngineerModel'). –

+0

Dada su edición, mi problema es que en el editor el modelo es de tipo 'EngineerModel' y el atributo no está en el modelo, está en la propiedad del modelo adjunto. Obviamente, el nombre de la propiedad podría cambiar y podría haber varias propiedades con el tipo 'EngineerModel' (así que no puedo obtener el tipo de modelo adjunto y encontrar la propiedad de tipo' EngineerModel'). –

+0

Acabo de leer los comentarios sobre la pregunta y lo que realmente desea es enumerar todas las propiedades que tienen '[Engineer (true)]'? –

Cuestiones relacionadas