自定义显示格式属性仅设置一次

本文关键字:一次 设置 显示格式 属性 自定义 | 更新日期: 2023-09-27 17:49:48

我正在通过以下代码在资源中的显示格式中设置 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
        {
        }
    }

我在视图模型中使用显示格式属性作为

  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; }
    }

自定义显示格式属性仅设置一次

以下是对问题所在的一些见解。

Mvc 使用一种形式的类型描述符 (AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type)( 来读取模型的属性。 类型描述符是缓存有关属性和属性的信息。 因此,就 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但没有运气

我知道的其余选项以一种或另一种方式不那么方便或不令人惊讶。 可能不推荐。

  1. 成功刷新AssociatedMetadataTypeTypeDescriptionProvider TypeDescriptors的某种方法。 我对这些不太熟悉,所以完全可以有一个。 我只是目前没有看到一个。
  2. 返工或创建自己的ModelMetadataProvider。 一切都是开源的,所以它是可能的,尽管我不确定我会推荐它,除非作为最后的手段。
  3. 您可以使用TypeDescriptor api在拉取属性时强制重新实例化属性。 请参阅 https://stackoverflow.com/a/12143653/897291。
  4. 直接在 MVC 中对所需属性进行建模(作为模型属性,而不是属性(。 可以是全新的属性,也可以是原始属性中的某种逻辑,当 null 返回其他内容时。 不过处理起来很尴尬。

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

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

的方法

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