WPF DataGrid基于对象类型和子类型的动态列
我正在构建一个WPF软件来管理电子元件库存。WPF DataGrid基于对象类型和子类型的动态列
我有以下结构:
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
(所以我会得到列制造商,PartNumber,电阻和电源)。同时,如果我筛选ListCollectionView
以获得Capacitor
子类型,则DataGrid
应具有Capacitor
类公共属性和Part
公共属性(制造商,零件编号,电容和电压)。 最后,如果没有应用过滤,DataGrid
将只显示Part
属性(制造商和部件编号)。
我试图用AutoGenerateColumns=true
但DataGrid
只显示Part
特性,即使我过滤ListCollectionView
只具有Resistors
。我也尝试将ObservableCollection
的类型更改为dynamic
,但它也不起作用。
如何根据ObservableCollection
中包含的对象的类型更改DataGrid
列?
这是使用autogenerate的解决方案。只需在可观察集合上实现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";
}
}
这里有一种方法可以做到这一点。不要自动生成列。设置每个可能的列。然后将每列的可见性绑定到转换器,以确定该列是否可见。
<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以获取集合中包含的派生类型的属性。
我用你的想法来创建布尔属性并将列可见性绑定到该属性。成功了! – RHaguiuda
这工作,但GetItemProperties仅在应用程序启动时调用。我需要在每次应用从ObservableCollection获取的ListViewCollection过滤时刷新它。这可能吗? – RHaguiuda
是的,但不是很优雅... dataGrid.ItemsSource = null; dataGrid.ItemsSource = PartCollection; – AQuirky
谢谢。很好地工作。 – RHaguiuda