【问题标题】:DisplayAttribute doesn't localize its properties in modelDisplayAttribute 不在模型中本地化其属性
【发布时间】:2013-01-29 00:32:51
【问题描述】:

我在我的 WPF 应用程序中使用 MVVM 模式,并将带有本地化的 DisplayAttribute 应用于我的模型的属性:

class MyModel
{
    [Display(
        ResourceType = typeof(Resources.Strings),
        Name = "MyPropertyName",
        Description = "MyPropertyDescription")]
    public double MyProperty { get; set; }
}

我想显示模型属性的本地化属性。必要的资源文件位于适当的位置,必要的文化设置。我还将 Build Action 设置为 Embedded Resource,并将 Custom Tool 设置为 PublicResXFileCodeGenerator - 根据 DisplayAttribute 的要求。但 DisplayAttribute 为其 Name 参数返回“MyPropertyName”而不是本地化字符串。

我使用 DisplayProperty 的场景如下所示。为了显示模型属性的属性,我使用了一个带有帮助类的转换器,如下所示:

namespace MyProject.Converters
{
    // helper class
    public class MetadataParameters
    {
        public Type ModelType { get; set; }
        public string ModelProperty { get; set; }
        public Type AttributeType { get; set; }
        public string AttributeProperty { get; set; }
    }

    public class MetadataConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var mp = parameter as MetadataParameters;
            var modelPropertyInfo = mp.ModelType.GetProperty(mp.ModelProperty);
            var attribute = modelPropertyInfo
                .GetCustomAttributes(true)
                .Cast<Attribute>()
                .FirstOrDefault(memberInfo => memberInfo.GetType() == mp.AttributeType);
            var attributeProperty = attribute.GetType().GetProperty(mp.AttributeProperty);

            return attributeProperty.GetValue(attribute, null);
        }
    }
}

XAML 资源:

xmlns:converters="clr-namespace:MyProject.Converters"
<converters:MetadataConverter x:Key="metadataConverter" />

XAML:

xmlns:converters="clr-namespace:MyProject.Converters"
xmlns:DataAnnotations="clr-namespace:System.ComponentModel.DataAnnotations;assembly=System.ComponentModel.DataAnnotations"
xmlns:Models="clr-namespace:MyProject.Models"

<TextBlock 
    <TextBlock.Text>
        <Binding
            Mode="OneWay"
            Converter="{StaticResource metadataConverter}">
            <Binding.ConverterParameter>
                <converters:MetadataParameters
                    ModelType="{x:Type Models:Model}"
                    ModelProperty="ModelProperty"
                    AttributeType="{x:Type DataAnnotations:DisplayAttribute}"
                    AttributeProperty="Name" />                            
            </Binding.ConverterParameter>
        </Binding>
    </TextBlock.Text>
</TextBlock>

我编写了自己的简单属性,它返回本地化字符串,而不仅仅是属性名称的值(如 DisplayAttribute 所做的那样):

public class LocalizedDisplayAttribute : Attribute
{
    private readonly string name;

    public virtual string Name
    {
        get
        {
            var rm = new System.Resources.ResourceManager(typeof(Resources.Strings));
            return rm.GetString(this.name);
        }
    }

    public LocalizedDisplayAttribute(string name)
        : base()
    {
        this.name = name;
    }
}


class MyModel
{
    [LocalizedDisplay("MyPropertyName")]
    public double MyProperty { get; set; }
}

那么为什么 DisplayAttribute 不本地化它的属性呢? MSDN 说这个属性是为本地化而设计的。在我的 ASP.NET MVC 项目中,DisplayAttribute 工作正常。

【问题讨论】:

    标签: c# wpf mvvm localization attributes


    【解决方案1】:

    DisplayAttribute 上有 Get 方法,还有一些您需要调用的其他方法,它们将为您提供您正在寻找的本地化字符串。您在这里所做的是获取 DisplayAttribute.Name 属性的值,即“MyPropertyName”。

    如果调用 DisplayAttribute.GetName(),它会查找 ResourceType 属性指定的资源类,然后它会使用 Name 属性来反映资源类型上的属性。

    我更改了您的代码,假设您请求的 AttributeProperty 将获得 GetXXX() 方法。

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      var mp = parameter as MetadataParameters;
      var modelPropertyInfo = mp.ModelType.GetProperty(mp.ModelProperty);
      var attribute = modelPropertyInfo
          .GetCustomAttributes(true)
          .Cast<Attribute>()
          .FirstOrDefault(memberInfo => memberInfo.GetType() == mp.AttributeType);
    
      // We have to call the GetXXX methods on the attribute to get a localised result.
      //return ((DisplayAttribute)attribute).GetName();
      var result = attribute
        .GetType()
        .InvokeMember(
          "Get" + mp.AttributeProperty,
          BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
          null,
          attribute,
          new object[0]); 
      return result;
    }
    

    【讨论】:

    • 我试过你的食谱,效果很好!谢谢。为方便起见,我只是将调用成员名称的硬编码字符串替换为expression
    • 感谢@base2 指出.Name 和.GetName 之间的区别。现在正在使用本地化。
    猜你喜欢
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2012-02-07
    相关资源
    最近更新 更多