仅自定义DisplayFormatAttribute设置一次

时间:2015-05-19 12:55:23

标签: c# asp.net-mvc asp.net-mvc-3 asp.net-mvc-4

我通过以下代码

从资源中设置DisplayFormat中的NullDisplayText
public class LocalizedDisplayFormatAttribute : DisplayFormatAttribute
{

    private readonly PropertyInfo _propertyInfo;


    public LocalizedDisplayFormatAttribute(string resourceKey, Type resourceType)
        : base()
    {
        this._propertyInfo = resourceType.GetProperty(resourceKey, BindingFlags.Static | BindingFlags.Public);
        if (this._propertyInfo == null)
        {
            return;
        }

        base.NullDisplayText = (string)this._propertyInfo.GetValue(this._propertyInfo.DeclaringType, null);
    }


    public new string NullDisplayText
    {
        get
        {
            return base.NullDisplayText;
        }

        set
        {
            base.NullDisplayText = value;
        }
    }
}

我使用的默认文化是“en-US”,一旦我将文化更改为es-AR并加载页面工作正常,但是当我将文化更改回en-US时,字段不会被转换回来。

我通过以下方式改变文化

protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        try
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies.Get("CurrentCulture");
            string culutureCode = cookie != null && !string.IsNullOrEmpty(cookie.Value) ? cookie.Value : "en";
            CultureInfo ci = new CultureInfo(culutureCode);
            System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
            System.Threading.Thread.CurrentThread.CurrentCulture =
            CultureInfo.CreateSpecificCulture(ci.Name);
        }
        catch
        {
        }
    }

我在ViewModel中使用DisplayFormat属性作为

  public class AlarmCodeDetailsViewModel
    {
        /// <summary>
        /// Gets or sets the alarm code ID
        /// </summary>
        public int AlarmCodeID { get; set; }

        /// <summary>
        /// Gets or sets the alarm code
        /// </summary>
        [LocalizedDisplayName("Label_AlarmCode")]
        [LocalizedDisplayFormatAttribute("Warning_NullDisplayText", typeof(Properties.Resources), HtmlEncode = false)]
        public string Code { get; set; }

        /// <summary>
        /// Gets or sets the Description
        /// </summary>
        [LocalizedDisplayName("Label_Description")]
        [LocalizedDisplayFormatAttribute("Warning_NullDisplayText", typeof(Properties.Resources), HtmlEncode = false)]
        public string Description { get; set; }

        /// <summary>
        /// Gets or sets the Notes
        /// </summary>
        [LocalizedDisplayName("Label_Notes")]
        [LocalizedDisplayFormatAttribute("Warning_NullDisplayText", typeof(Properties.Resources), HtmlEncode = false)]
        public string Notes { get; set; }
    }

1 个答案:

答案 0 :(得分:7)

以下是对错误的了解。

Mvc正在使用TypeDescriptor(AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type))的形式来读取模型中的属性。 TypeDescriptors缓存有关属性和属性的信息。因此,根据TypeDescriptor api,您的LocalizedDisplayFormatAttribute属性只会被实例化一次,这意味着资源信息只读取一次(在构造时)。请参阅答案的底部以获取参考。

无效的解决方案

  1. 眨眼的反应是每次通过getter访问时从LocalizedDisplayFormatAttribute NullDisplayText中提取最新的资源信息。很遗憾,DisplayFormatAttribute NullDisplayText不是虚拟的,您使用new关键字隐藏了该属性。这不适用于多态分派视角(Mvc将getter称为DisplayFormatAttribute而不是LocalizedDisplayFormatAttribute,因此永远不会调用您的阴影属性)

  2. 我尝试TypeDescriptor.Refresh()重载https://msdn.microsoft.com/en-us/library/z1ztz056(v=vs.110).aspx但没有运气

  3. 我所知道的其余选项在某种程度上并不方便或不令人惊讶。可能不推荐。

    1. 成功刷新AssociatedMetadataTypeTypeDescriptionProvider TypeDescriptors的一些方法。我对这些不太熟悉,所以总有一个。我现在只是没见到。
    2. 返工或创建自己的ModelMetadataProvider。一切都是开源的,所以它可能,但我不确定我会推荐它,除非作为最后的手段。
    3. 您可以使用TypeDescriptor api强制在拉动属性时重新实例化。见https://stackoverflow.com/a/12143653/897291
    4. 直接在MVC中建模所需的属性(作为模型属性,而不是属性)。既可以是全新的属性,也可以在原始属性中使用某种逻辑,当null返回其他内容时。虽然很难处理。
    5. 我知道,没什么好看的。也许这会给别人足够的洞察力来提出更好的东西?

      要自行验证,请参阅 调用CreateMetaData方法设置SetFromDataTypeAndDisplayAttributes

      https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs result.NullDisplayText = displayFormatAttribute.NullDisplayText;方法

      DataAnnotationsModelMetadataProvider扩展AssociatedMetadataProvider,这对于传递属性是可行的。请参阅https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/AssociatedMetadataProvider.cs GetMetadataForProperty方法作为示例。