【问题标题】:Customized DisplayFormatAttribute only setting once自定义的 DisplayFormatAttribute 只设置一次
【发布时间】:2015-05-19 12:55:22
【问题描述】:

我通过以下代码在资源的 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; }
    }

【问题讨论】:

  • 你们如何改变文化?请分享您的更改方法/代码。请使用 LocalizedDisplayFormatAttribute 分享您的 View Model 代码声明。
  • @Dave Alperovich:我已经编辑了我的问题
  • 请帮帮我。我对问题中的一些措辞感到困惑。你说但是当我改变文化时它不会影响NullDisplayText,它只设置一次我读到这意味着你的应用程序读取文化设置一次并设置NullDisplayText一次。这可能不是你的意思,因为文化只会设置一次,所以似乎没有问题。
  • 我猜你的意思是 NullDisplayText 的设置应该与它不同。如果是这样,请更详细地解释。您获得的文化是什么,NullDisplayText 的预期价值与您获得的价值是什么。
  • @DaveAlperovich:我使用的默认文化是“en-US”,一旦我将文化更改为 es-AR 并加载页面,它的工作正常,但是当我将文化更改回 en-US字段没有被转换回来。

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


【解决方案1】:

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

Mvc 使用一种 TypeDescriptor (AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type)) 来读取模型的属性。 TypeDescriptor 缓存有关属性和属性的信息。因此,就 TypeDescriptor api 而言,您的 LocalizedDisplayFormatAttribute 属性仅被实例化一次,这意味着资源信息仅被读取一次(在构造时)。参考答案见底部。

不起作用的解决方案

  1. 每次通过 getter 访问时,闪烁的反应是从您的 LocalizedDisplayFormatAttribute NullDisplayText 中提取最新的资源信息。不幸的是 DisplayFormatAttribute NullDisplayText 不是虚拟的,并且您正在使用 new 关键字隐藏该属性。从多态调度的角度来看,这是行不通的(Mvc 将 getter 称为 DisplayFormatAttribute 而不是 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 来强制在您的属性被拉取时重新实例化它。见https://stackoverflow.com/a/12143653/897291
  4. 直接在 MVC 中为所需的属性建模(作为模型属性,而不是属性)。可以是全新的属性,也可以在原始属性中包含某种逻辑,当 null 返回其他内容时。不过处理起来很尴尬。

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

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

DataAnnotationsModelMetadataProvider 扩展 AssociatedMetadataProvider 负责传递属性。以https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/AssociatedMetadataProvider.csGetMetadataForProperty方法为例。

【讨论】:

    猜你喜欢
    • 2014-07-09
    • 2016-06-18
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-27
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    相关资源
    最近更新 更多