0

モデル プロパティの属性をビューにバインドする方法は?

たとえば、次のようなモデルがあります。

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

そして、私のビューモデルは次のようなものです(異常ではありません):

public class MyVM
{
    private Models.MyModel model;

    public string MyVMProperty
    {
        get { return model.MyProperty.ToString(); }
        set
        {
            // some usual code with parsing a value from textbox...
        }
    }
}

ビューでは、モデル プロパティの属性からデータをバインドしたいと考えています。このようなもの:

<Grid Name="myGrid">
    <TextBox 
        Text="{Binding Path=MyVMProperty}" 
        />

    <TextBlock 
        Text="{Binding Path=MyVM.model.MyProperty.DisplayAttribute.Name}" 
        />

    <TextBlock 
        Text="{Binding Path=MyVM.model.MyProperty.DisplayAttribute.Description}" 
        />
</Grid>

そして、コードのどこかで私は:

myGrid.DataContext = new MyVM();

入手方法は?

4

2 に答える 2

1

属性プロパティはリフレクションを使用してのみ取得できるため、「(クラス OR オブジェクト) + プロパティ名」タプルを、これらの属性の値を公開するものに変換する手段を提供する必要があります。

非常に具体的な解決策は次のようになります

public DisplayAttribute MyVMPropertyDisplayAttribute
{
    get
    {
        var prop = typeof(MyModels.Model).GetProperty("MyProperty");
        var attr = prop.GetCustomAttributes(typeof(DisplayAttribute));
        return attr.Cast<DisplayAttribute>().Single();
    }
}

そして、たとえばにバインドできますMyVMPropertyDisplayAttribute.Name

明らかに、このソリューションは、さまざまなモデルや属性タイプで便利に使用できるように一般化する必要があります。代わりに、値コンバーター内にパッケージ化することをお勧めします。

于 2013-01-26T16:07:13.443 に答える
1

考えられる解決策の 1 つは、ヘルパー クラスを追加し、そのクラスのインスタンスをコンバーター パラメーターとして渡すことです。インスタンスは、手動で XAML で初期化する必要があります。インスタンスは、モデル インスタンスのプロパティの属性の値を取得するために必要なすべてのデータで構成されます。ソリューションは一般化されており、コンバーター ロジック内にハードコーディングされたデータはありません。コンバーターの「値」パラメーターも必要ありません。

したがって、結果は次のようになります。

ビューモデルと同じアセンブリ内の何か。コンバーターとヘルパー クラス (簡素化 - null チェックなどなし):

namespace MyProject.Converters
{
    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);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

リソース ファイル (XAML):

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

ビュー ファイル内:

<!-- language: lang-xml -->

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>
于 2013-01-27T17:34:53.980 に答える