我正在构建一个WPF软件来管理电子元件库存。
我有以下结构:
public class Part
{
public string Manufacturer { get; set; }
public string PartNumber { get; set; }
}
public class Resistor : Part
{
public string Resistance { get; set;}
public string Power { get; set;}
}
public class Capacitor : Part
{
public string Capacitance { get; set; }
public string Voltage { get; set; }
}
电阻器和电容器是Part的子类型。
我将DataGrid
绑定到ObservableCollection<Part>
,并使用ListCollectionView
添加过滤和分组功能。
我想要完成的是当我过滤ListCollectionView
以仅获取Resistor
子类型时,我希望DataGrid
将其更新为显示Resistor
类型及其基类Part
的属性(因此我会得到制造商,PartNumber,Resistance和Power列)。同时,如果我过滤ListCollectionView
获取Capacitor
子类型,则DataGrid
应具有Capacitor
类公共属性和Part
公共属性(制造商,PartNumber,电容和电压)。
最后,如果没有应用过滤,则DataGrid
只会显示Part
属性(制造商和PartNumber)。
我尝试使用AutoGenerateColumns=true
,但DataGrid
仅显示Part
属性,即使我将ListCollectionView
过滤为只有Resistors
。我还尝试将ObservableCollection
的类型更改为dynamic
,但它也没有。
如何根据DataGrid
中包含的对象类型更改ObservableCollection
列?
答案 0 :(得分:3)
这是一种方法。不要自动生成列。设置每个可能的列。然后将每列的可见性绑定到确定列是否可见的转换器。
<FrameworkElement x:Name="dummyElement" Visibility="Collapsed"/>
<DataGrid x:Name="dataGrid" ItemsSource="{Binding PartCollection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Manufacturer" Binding="{Binding Manufacturer}"/>
<DataGridTextColumn Header="Part Number" Binding="{Binding PartNumber}" />
<DataGridTextColumn Header="Power" Binding="{Binding Power}" Visibility="{Binding DataContext.PartCollection, Source={x:Reference dummyElement}, Converter={StaticResource ColumnVisibility}, ConverterParameter=Resistor}"/>
<DataGridTextColumn Header="Resistance" Binding="{Binding Resistance}" Visibility="{Binding DataContext.PartCollection, Source={x:Reference dummyElement}, Converter={StaticResource ColumnVisibility}, ConverterParameter=Resistor}"/>
<DataGridTextColumn Header="Capacitance" Binding="{Binding Capacitance}" Visibility="{Binding DataContext.PartCollection, Source={x:Reference dummyElement}, Converter={StaticResource ColumnVisibility}, ConverterParameter=Capacitor}"/>
<DataGridTextColumn Header="Voltage" Binding="{Binding Voltage}" Visibility="{Binding DataContext.PartCollection, Source={x:Reference dummyElement}, Converter={StaticResource ColumnVisibility}, ConverterParameter=Capacitor}"/>
</DataGrid.Columns>
</DataGrid>
这是转换器的静态资源......
<Window.Resources>
<local:ColumnVisibilityConverter x:Key="ColumnVisibility"/>
</Window.Resources>
这是转换器...
public class ColumnVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ObservableCollection<Part> collection = value as ObservableCollection<Part>;
string collectionType = parameter as string;
if(collection != null && collectionType != null && collection.Count > 0)
{
switch(collectionType)
{
case "Resistor": return collection[0].GetType() == typeof(Resistor) ? Visibility.Visible : Visibility.Hidden;
case "Capacitor": return collection[0].GetType() == typeof(Capacitor) ? Visibility.Visible : Visibility.Hidden;
default: return Visibility.Hidden;
}
}
return Visibility.Hidden;
}
我对数据网格列的绑定可见性进行了一些努力。在这里找到答案:Binding Visibility for DataGridColumn in WPF
在我看来,手动设置列是最佳做法。如果你真的想自动生成它们,还有另一种方法可以做到这一点。您可以在集合上实现ICustomTypeDescriptor,以返回PropertyDescriptors,以获取集合中包含的派生类型的属性。
答案 1 :(得分:1)
这是使用自动生成的解决方案。只需在observable集合上实现ITypedList接口......
public class Parts : ObservableCollection<Part>, ITypedList
{
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
if(Count == 0)
{
return TypeDescriptor.GetProperties(typeof(Part));
}
else
{
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(this[0]);
return pdc;
}
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
return "Parts";
}
}