Я создаю программное обеспечение 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 публичные свойства ( Производитель, номер детали, емкость и напряжение). Наконец, если фильтрация не применяется, DataGrid будет отображать только свойства Part (Manufacturer и PartNumber).

Я пытался использовать AutoGenerateColumns=true, но DataGrid показывает только свойства Part, даже если я фильтрую ListCollectionView, чтобы иметь только Resistors. Я также попытался изменить тип ObservableCollection на dynamic, но это тоже не сработало.

Как я могу изменить столбцы DataGrid в зависимости от типа объекта, содержащегося в ObservableCollection?

2
RHaguiuda 28 Фев 2017 в 21:26

2 ответа

Лучший ответ

Вот решение с использованием автогенерации. Просто реализуйте интерфейс 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";
    }
}
1
AQuirky 1 Мар 2017 в 18:50

Вот один из способов сделать это. Не создавать автоматически столбцы. Настройте каждый столбец, который возможен. Затем свяжите видимость каждого столбца с конвертером, который определяет, является ли столбец видимым.

    <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;
    }

Я немного боролся с привязкой видимости к столбцу таблицы данных. Нашел ответ здесь: Видимость привязки для DataGridColumn в WPF

На мой взгляд, установка колонок вручную - лучшая практика. Если вы действительно хотите их сгенерировать, есть другой способ сделать это. Вы можете реализовать ICustomTypeDescriptor в своей коллекции, чтобы возвращать PropertyDescriptors для свойств производного типа, который содержится в коллекции.

4
Community 23 Май 2017 в 11:46