2012-03-09 12 views
6

Creé una clase de atributo para adjuntar metadatos a las propiedades, por lo que puedo mostrar información sobre herramientas para los campos de entrada del formulario.IMetadataAware.OnMetadataCreated nunca se llama

HelpAttribute implementa IMetadataAware:

Public Class HelpAttribute 
    Inherits Attribute 
    Implements System.Web.Mvc.IMetadataAware 

    Public Sub New(text As String) 
     _text = text 
    End Sub 

    Private _text As String 
    Public ReadOnly Property Text As String 
     Get 
      Return _text 
     End Get 
    End Property 

    Public Sub OnMetadataCreated(metadata As System.Web.Mvc.ModelMetadata) Implements System.Web.Mvc.IMetadataAware.OnMetadataCreated 
     metadata.AdditionalValues.Add("HelpText", _text) 
    End Sub 
End Class 

que utilizan estos metadatos en mi método de extensión:

<Extension()> 
Public Function HelpFor(Of TModel, TProperty)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty))) As MvcHtmlString 
    Dim metaData = ModelMetadata.FromLambdaExpression(Of TModel, TProperty)(expression, htmlHelper.ViewData) 

    If metaData.AdditionalValues.ContainsKey("HelpText") Then 
     Dim helpText = metaData.AdditionalValues("HelpText") 
     Return MvcHtmlString.Create(String.Format("<span class=""help""></span><div class=""tooltip"" style=""display: none""><div class=""border-top""></div><div class=""close""><a href=""#"">close</a></div><br class=""clear""><div class=""content"">{1}</div></div>", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(metaData.PropertyName), helpText, metaData.DisplayName)) 
    End If 

    Return MvcHtmlString.Create(String.Format("<span class=""no_help""></span>", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(metaData.PropertyName), metaData.DisplayName)) 
End Function 

por lo que puedo llamar Html.HelpFor para cualquiera de las propiedades de mi modelo y si tiene metadatos apropiados que mostrar un icono de ayuda que muestra la información sobre herramientas al hacer clic (js).

Todo funciona bien siempre que HelpAttribute se defina en el mismo ensamblaje que las clases con las que decorar sus propiedades. Hoy tuve que mover HelpAttribute a una dll separada (también diferente espacio de nombres), así que lo hice, hice referencia al proyecto y esperé que funcionara. No recibo ningún error de compilación, la aplicación funciona bien, pero no muestra los íconos de ayuda. Depuré el código y veo que el constructor de HelpAttribute se llama para diferentes propiedades con un texto adecuado, pero OnMetadataCreated nunca se llama. ¿Alguien tiene una idea de por qué es eso y cómo solucionarlo?

Respuesta

2

Una vez más, responderé a mi pregunta por mi cuenta. Aparentemente publicar cosas en SO me ayuda a estructurar el problema en mi cabeza. Cuando moví HelpAttribute a una biblioteca de clases separada, tuve que hacer referencia a System.Web.Mvc para la interfaz IMetadataAware. Yo uso .NET 4.0 y me refiero automáticamente a MVC4 que instalé hace algún tiempo con fines de prueba. No me dio ningún error, simplemente no funcionó. Cuando cambié System.web.Mvc a ver. 3.0 todo funciona sin problemas.

-2
using System; 
    using System.Collections.Generic; 
    using System.Globalization; 
    using System.Web; 
    using System.Web.Mvc; 

    namespace ColorPickerAttributeExample.Attributes 
    { 
     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 
     public sealed class ColorPickerAttribute : Attribute, IMetadataAware 
     { 
      private const string Template = 
       "$('#{0}').ColorPicker({{onSubmit: function(hsb, hex, rgb, el) {{" + 
       "var self = $(el); self.val(hex);self.ColorPickerHide();}}, onBeforeShow: function() " + 
       "{{$(this).ColorPickerSetColor(this.value);}}}}).bind('keyup', function(){{ $(this).ColorPickerSetColor(this.value); }});"; 

      public const string ColorPicker = "_ColorPicker"; 

      private int _count; 

      // if using IoC container, you could inject this into the attribute 
      internal HttpContextBase Context 
      { 
       get { return new HttpContextWrapper(HttpContext.Current); } 
      } 

      public string Id 
      { 
       get { return "jquery-colorpicker-" + _count; } 
      } 

      #region IMetadataAware Members 

      public void OnMetadataCreated(ModelMetadata metadata) 
      { 
       IList<string> list = Context.Items["Scripts"] as IList<string> ?? new List<string>(); 
       _count = list.Count; 

       metadata.TemplateHint = ColorPicker; 
       metadata.AdditionalValues[ColorPicker] = Id; 

       list.Add(string.Format(CultureInfo.InvariantCulture, Template, Id)); 

       Context.Items["Scripts"] = list; 
      } 

      #endregion 
     } 
    } 



    using ColorPickerAttributeExample.Attributes; 
    using System; 

    namespace ColorPickerAttributeExample.Models 
    { 
     public class HomeModel 
     { 
      [ColorPicker] 
      public string ColorPicker { get; set; } 
      [ColorPicker] 
      public DateTime ColorPicker2 { get; set; } 
     } 
    } 


@model dynamic 

@{ 
    var picker = ViewData.GetModelAttribute<ColorPickerAttribute>(); 
    if (picker != null) 
    { 
     @Html.LabelForModel() 
     @Html.TextBoxFor(m => m, new {id = ViewData.ModelMetadata.AdditionalValues[ColorPickerAttribute.ColorPicker]}) 
    } 
} 
+0

El código publicado aquí no se refiere a la cuestión planteada, es sólo un atributo repetitivo sin considerar el contexto del problema de OP Incluso si el código fuera de alguna utilidad, no debería ser arrojado sin ceremonias sin alguna explicación de lo que hace y cómo responde la pregunta original. – RobD

13

Otra razón esto no puede ser llamado es si usted tiene el espacio de nombres mal referenciado. Así

using System.Web.ModelBinding; 

compilará y no ser golpeado, pero usted debe utilizar

using System.Web.Mvc; 
+0

¡Gracias! No quiero imaginar cuánto me tomaría resolver esto. – Gerino

Cuestiones relacionadas