2010-06-30 105 views
8

我有一個對象集合,存儲在CollectionViewSource中並綁定到DataGrid我想在DataGrid中顯示當前所選對象的'詳細視圖'。我可以使用CollectionViewSource.View.CurrentItem獲得當前對象。WPF:將列表動態綁定到(某些)對象的屬性

MyClass 
{ 
    [IsImportant] 
    AProperty{} 

    AnotherProperty{} 

    [IsImportant] 
    YetAnotherProperty{} 
} 

我想這樣做是在一個列表框顯示一個標籤(與屬性名)和控制(編輯),對每個屬性的標有IsImportant屬性。綁定必須在所做的編輯,DataGrid和後臺對象之間起作用。顯示的控件應根據屬性的類型而有所不同,可以是boolean,stringIEnumerable<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中,那也可以。

回答

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設置爲各種編輯器模板之一來完成此操作。這個例子使用一個複選框,如果該屬性是一個布爾否則一個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> 

然後,你可以創建你的列表框爲:

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

這看起來太棒了;我會盡快實施它,並讓你知道它是如何發生的。謝謝! – 2010-07-01 16:53:26

+0

這個工程大多很棒。我剛剛向PropertyValueConverter添加了一個空檢查,因爲它在第一次設置綁定時正在接收一個空對象。唯一的問題是,目前,如果我更改此控件的值,它不會傳播到數據網格。據推測支持對象正在改變,因爲改變的值仍然由itemscontrol顯示,但網格沒有被通知。這是否與Binding.DoNothing? – 2010-07-01 19:27:08

+1

@Daniel:如果您想讓一個控件所做的更新反映到綁定到同一個屬性的其他控件中,您的對象將需要實現INotifyPropertyChanged。您還需要在PropertyValue上實現INotifyPropertyChanged。 PropertyValueConverter是用於ItemsSource綁定本身的,這是單向的,所以ConvertBack不會被調用,而Binding.DoNothing也不會有問題。 – Quartermeister 2010-07-02 02:54:49