我正在构建一个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; }
}
电阻和电容器是部分的亚型。
我将DataGrid
绑定到ObservableCollection<Part>
,并使用ListCollectionView
添加过滤和分组功能。
我要完成的工作是当我过滤ListCollectionView
仅获取Resistor
子类型时,我希望DataGrid
更新其列以显示Resistor
类型的属性,并且它的基础类Part
(因此,我将获得列列制造商,党派,电阻和功率)。同时,如果我过滤ListCollectionView
以获取Capacitor
子类型,则DataGrid
应具有Capacitor
类公共属性和Part
公共属性(制造商,Partnumber,电容和电压)。最后,如果没有使用过滤,DataGrid
将仅显示Part
属性(制造商和Partnumber)。
我尝试使用AutoGenerateColumns=true
,但是DataGrid
仅显示Part
属性,即使我过滤ListCollectionView
仅具有Resistors
。我还尝试将ObservableCollection
的类型更改为dynamic
,并且也不起作用。
如何根据ObservableCollection
中包含的对象的类型更改DataGrid
列?
这是一种方法。不要自动生成列。设置每个可能的列。然后将每列的可见性绑定到确定列是否可见的转换器。
<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;
}
我对数据网格列的可见性有些挣扎。在此处找到答案:wpf
中datagridcolumn的绑定可见性在我看来,手动设置列是最佳实践。如果您真的想自动化它们,那么还有另一种方法可以做到这一点。您可以在集合上实现一个iCustomTypedScriptor,以返回集合中包含的派生类型的属性的属性描述器。
这是使用自动化的解决方案。只需在可观察的集合上实现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";
}
}