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

Dan*_*ake 9 c# data-binding wpf binding

我有一个对象的集合存储在一个CollectionViewSource并绑定到一个DataGrid.我想显示当前所选对象的"详细视图"DataGrid.我可以使用获取当前对象CollectionViewSource.View.CurrentItem.

MyClass
{
    [IsImportant]   
    AProperty{}

    AnotherProperty{}

    [IsImportant]
    YetAnotherProperty{}
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Qua*_*ter 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); }
    }
}
Run Code Online (Sandbox Code Playgroud)

您希望将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;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一个技巧是你希望编辑控件根据属性的类型而变化.您可以通过使用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>
Run Code Online (Sandbox Code Playgroud)

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

<ItemsControl ItemsSource="{Binding Converter={StaticResource PropertyValueConverter}}"/>
Run Code Online (Sandbox Code Playgroud)