WPFアプリケーションでMVVMパターンを使用し、ローカリゼーションを使用してDisplayAttributeをモデルのプロパティに適用します。
class MyModel
{
[Display(
ResourceType = typeof(Resources.Strings),
Name = "MyPropertyName",
Description = "MyPropertyDescription")]
public double MyProperty { get; set; }
}
モデルプロパティのローカライズされた属性プロパティを表示したいと思います。必要なリソースファイルが適切な場所に配置され、必要なカルチャが設定されます。また、DisplayAttributeの必要に応じて、ビルドアクションを埋め込みリソースとして設定し、カスタムツールをPublicResXFileCodeGeneratorとして設定します。ただし、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.NETMVCプロジェクトではDisplayAttributeが正しく機能します。