WPF:将列表动态绑定到(某些)对象的属性

时间:2010-06-30 19:11:25

标签: c# wpf data-binding binding

我有一组存储在CollectionViewSource中并绑定到DataGrid的对象。 我想显示DataGrid 中当前所选对象的“详情视图”。我可以使用CollectionViewSource.View.CurrentItem获取当前对象。

MyClass
{
    [IsImportant]   
    AProperty{}

    AnotherProperty{}

    [IsImportant]
    YetAnotherProperty{}
}

我想要做的是在列表框中显示标签(带有属性名称)和控件(用于编辑),每个属性都标有IsImportant属性。绑定必须在所做的编辑,DataGrid和后备对象之间起作用。显示的控件应根据属性的类型而有所不同,可以是booleanstringIEnumerable<string>(我已编写IValueConverter以在可枚举和换行符分隔之间进行转换字符串)。

有谁知道实现此目的的方法?我现在可以通过以下方式显示每个属性的值,但编辑它们不会更新后备对象:

listBox.ItemsSource = from p in typeof(MyClass).GetProperties()
                      where p.IsDefined(typeof(IsImportant), false)
                      select p.GetValue(_collectionViewSource.View.CurrentItem, null);

为了澄清,我希望这可以'自动'发生,而无需在XAML中手动指定属性名称。如果我可以在运行时基于哪些属性标记属性动态添加到XAML ,那也没关系。

1 个答案:

答案 0 :(得分:12)

您希望具有带属性名称和控件的标签的控件编辑属性值,因此首先创建一个包装特定对象的属性的类,以充当该控件的DataContext:

public class PropertyValue
{
    private PropertyInfo propertyInfo;
    private object baseObject;

    public PropertyValue(PropertyInfo propertyInfo, object baseObject)
    {
        this.propertyInfo = propertyInfo;
        this.baseObject = baseObject;
    }

    public string Name { get { return propertyInfo.Name; } }

    public Type PropertyType { get { return propertyInfo.PropertyType; } }

    public object Value
    {
        get { return propertyInfo.GetValue(baseObject, null); }
        set { propertyInfo.SetValue(baseObject, value, null); }
    }
}

您希望将ListBox的ItemsSource绑定到对象以使用这些控件填充它,因此创建一个IValueConverter,它将对象转换为PropertyValue对象的列表以获取其重要属性:

public class PropertyValueConverter
    : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return
            from p in value.GetType().GetProperties()
            where p.IsDefined(typeof(IsImportant), false)
            select new PropertyValue(p, value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

最后一个技巧是你希望编辑控件根据属性的类型而变化。您可以通过使用ContentControl并根据属性类型将ContentTemplate设置为各种编辑器模板之一来实现。如果属性是布尔值,则此示例使用CheckBox,否则使用TextBox:

<DataTemplate x:Key="CheckBoxTemplate">
    <CheckBox IsChecked="{Binding Value}"/>
</DataTemplate>
<DataTemplate x:Key="TextBoxTemplate">
    <TextBox Text="{Binding Value}"/>
</DataTemplate>
<Style x:Key="EditControlStyle" TargetType="ContentControl">
    <Setter Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding PropertyType}" Value="{x:Type sys:Boolean}">
            <Setter Property="ContentTemplate" Value="{StaticResource CheckBoxTemplate}"/>
        </DataTrigger>
    </Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type local:PropertyValue}">
    <StackPanel Orientation="Horizontal">
        <Label Content="{Binding Name}"/>
        <ContentControl Style="{StaticResource EditControlStyle}" Content="{Binding}"/>
    </StackPanel>
</DataTemplate>

然后,您可以将ListBox创建为:

<ItemsControl ItemsSource="{Binding Converter={StaticResource PropertyValueConverter}}"/>