Работа с DataGrid и ComboBoxes может быстро усложниться, поэтому давайте сделаем один шаг за раз с некоторыми объяснениями между ними.Я дал вам полные классы для кода во фрагментах.
Для начала я буду придерживаться модели MVVM и использовать модель-view-viewmmodel для привязки данных к DataGrid.Модель представления будет содержать списки значений Type
и SubType
, а также список строк.Класс модели для нашей строки я назову TypeModel
:
public class TypeModel
{
public string Type { get; set; }
public string SubType { get; set; }
}
Я не знаю, как вы определите, что SubType
действительно для данного Type
, но для этого примера я буду использоватьсловарь для настройки отношений в модели представления.
Таким образом, наша модель представления может выглядеть примерно так:
public class MainWindowViewModel
{
public ObservableCollection<TypeModel> Collection { get; set; }
public ObservableCollection<string> Type { get; set; }
public Dictionary<string, List<string>> SubTypeCollection { get; set; }
public MainWindowViewModel()
{
Collection = new ObservableCollection<TypeModel>();
TypeCollection = new ObservableCollection<string>()
{
"Type 1","Type 2","Type 3"
};
SubTypeCollection = new Dictionary<string, List<string>>()
{
{
TypeCollection[0], new List<string>()
{
"Type 1 - Sub type 0",
"Type 1 - Sub type 1"
}
},
{
TypeCollection[1], new List<string>()
{
"Type 2 - Sub type 0",
"Type 2 - Sub type 1",
"Type 2 - Sub type 2",
"Type 3 - Sub type 3",
}
},
{
TypeCollection[2], new List<string>()
{
"Type 3 - Sub type 0",
"Type 3 - Sub type 1",
"Type 3 - Sub type 2",
}
}
};
}
}
Теперь давайте настроим наше (начальное) представление (добавим к этому позже):
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Width="600"
Height="500">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<DataGrid
AutoGenerateColumns="False"
ItemsSource="{Binding Collection}">
<DataGrid.Columns>
<DataGridComboBoxColumn
Header="Type"
SelectedItemBinding="{Binding Type, UpdateSourceTrigger=PropertyChanged}"> <!-- property changed so we get the change right after we select-->
<DataGridComboBoxColumn.ElementStyle>
<Style
TargetType="ComboBox">
<Setter
Property="ItemsSource"
Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TypeCollection}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style
TargetType="ComboBox">
<Setter
Property="ItemsSource"
Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TypeCollection}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
<DataGridComboBoxColumn
Header="Sub Type"
SelectedItemBinding="{Binding SubType}">
<!-- How do we bind to the ItemSource based on the selected type?-->
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Итак, ваш фундаментальный вопрос заключается в том, как заполнить этот закомментированный раздел.
Вероятно, есть много способов сделать это - самым простым в моем уме было бы использоватьIMultiValueConverter
Это принимает две привязки:
- выбранная
Type
строка - словарь
TypeCollection
Так что этот класс будет выглядеть такэто (вы действительно можете использовать это для всех преобразований string
в list<string>
):
public class TypeToSubTypesConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null) return null;
if (values[0] == null || values[0] == DependencyProperty.UnsetValue) return null;
var type = values[0].ToString();
if (values[1] == null || values[1] == DependencyProperty.UnsetValue) return null;
var subTypeList = values[1] as Dictionary<string, List<string>>;
if (subTypeList == null) return null;
return subTypeList[type];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
Теперь последним шагом будет:
- Добавить ресурс конвертера вview
- Добавьте мультисвязывание к свойству
value
каждого setter
для ItemsSource
второгоПоле со списком
Итак, полный .xaml выглядит так:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Width="600"
Height="500">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<local:TypeToSubTypesConverter
x:Key="TypeToSubTypesConverter" />
</Window.Resources>
<Grid>
<DataGrid
AutoGenerateColumns="False"
ItemsSource="{Binding Collection}">
<DataGrid.Columns>
<DataGridComboBoxColumn
Header="Type"
SelectedItemBinding="{Binding Type, UpdateSourceTrigger=PropertyChanged}"> <!-- property changed so we get the change right after we select-->
<DataGridComboBoxColumn.ElementStyle>
<Style
TargetType="ComboBox">
<Setter
Property="ItemsSource"
Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TypeCollection}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style
TargetType="ComboBox">
<Setter
Property="ItemsSource"
Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TypeCollection}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
<DataGridComboBoxColumn
Header="Sub Type"
SelectedItemBinding="{Binding SubType, UpdateSourceTrigger=PropertyChanged}"> <!-- property changed so we get the change right after we select-->
<DataGridComboBoxColumn.ElementStyle>
<Style
TargetType="ComboBox">
<Setter
Property="ItemsSource">
<Setter.Value>
<MultiBinding
Converter="{StaticResource ResourceKey=TypeToSubTypesConverter}">
<Binding
Path="Type" />
<Binding
Path="DataContext.SubTypeCollection"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style
TargetType="ComboBox">
<Setter
Property="ItemsSource">
<Setter.Value>
<MultiBinding
Converter="{StaticResource ResourceKey=TypeToSubTypesConverter}">
<Binding
Path="Type" />
<Binding
Path="DataContext.SubTypeCollection"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>