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

然后你可以绑定到 eg MyVMPropertyDisplayAttribute.Name

显然,这个解决方案需要泛化,以便可以方便地跨不同的模型和属性类型使用;最好将其封装在值转换器中。

于 2013-01-26T16:07:13.443 回答
1

一种可能的解决方案是添加辅助类并将该类的实例作为转换器参数传递。必须手动在 XAML 中初始化该实例。该实例包含获取模型实例属性的属性值所需的所有数据。该解决方案是通用的,转换器逻辑内部没有硬编码数据。转换器的“值”参数也不是必需的。

因此,结果如下所示:

与视图模型在同一个程序集中的东西。转换器和助手类(简化 - 没有任何空检查等):

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 回答