仅自定义DisplayFormatAttribute设置一次

Jus*_* CI 22 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用的默认文化是"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
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

我在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; }
    }
Run Code Online (Sandbox Code Playgroud)

Ken*_*Ito 7

这里有一些关于什么是错的洞察力.

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

解决方案不起作用

  1. 眨眼的反应是从LocalizedDisplayFormatAttribute NullDisplayText每次通过getter访问时提取最新的资源信息.不幸的DisplayFormatAttribute NullDisplayText是,它不是虚拟的,而是用new关键字隐藏属性.从多态调度的角度来看,这不起作用(Mvc将getter称为a DisplayFormatAttribute而不是a LocalizedDisplayFormatAttribute,因此永远不会调用您的shadowed属性)

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

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

  1. 一些成功刷新的方法AssociatedMetadataTypeTypeDescriptionProvider TypeDescriptors.我对这些不太熟悉,所以总有一个.我现在还没有看到一个.
  2. 返工或创建ModelMetadataProvider自己的.一切都是开源的,所以它可能,虽然我不确定我会推荐它,除非作为最后的手段.
  3. 您可以使用TypeDescriptor api来强制在拉动属性时重新实例化.请参阅/sf/answers/850055741/.
  4. 直接在MVC中建模所需的属性(作为模型属性,而不是属性).既可以是全新的属性,也可以在原始属性中使用某种逻辑,当null返回其他内容时.虽然很难对付.

没什么了不起的,我知道.也许这会给别人足够的洞察力来提出更好的东西?

要自行验证,请参阅 调用方法设置的https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs CreateMetaData方法SetFromDataTypeAndDisplayAttributesresult.NullDisplayText = displayFormatAttribute.NullDisplayText;

DataAnnotationsModelMetadataProviderextends AssociatedMetadataProvider是传递属性的可扩展的.以https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/AssociatedMetadataProvider.cs GetMetadataForProperty方法为例.