Option 1
You can create your a DataGridTemplateColumn with two combobox. The first one can be populated with items from the main ViewModel and the second one will be bound to the items of the SelectedItem of the first.
<Window x:Class="WpfApplication1.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="525"
Height="350"
mc:Ignorable="d">
<Window.DataContext>
<local:Root/>
</Window.DataContext>
<Grid x:Name="LayoutRoot">
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Ch}" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ComboBox Width="100" ItemsSource="{Binding DataContext.ComboBox1Items, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" x:Name="ComboBox1"/>
<ComboBox Grid.Column="1" Width="100" ItemsSource="{Binding SelectedItem.Items, ElementName=ComboBox1}" SelectedItem="{Binding TheSettings}" IsEditable="True" IsReadOnly="True"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
public class ComboBox1Item
{
public string Label { get; set; }
public List<string> Items { get; set; }
public override string ToString()
{
return this.Label;
}
}
public class Root
{
public List<Channel> Ch { get; set; }
public List<ComboBox1Item> ComboBox1Items { get; set; }
public Root()
{
this.Ch = new List<Channel>(){
new Channel(){ TheSettings = "Settings1"},
new Channel(){ TheSettings = "Settings2"},
};
this.ComboBox1Items = new List<ComboBox1Item>{
new ComboBox1Item(){ Label = "Item1",
Items = new List<string>(){ "Settings1", "Settings2"}
},
new ComboBox1Item(){ Label = "Item2",
Items = new List<string>(){ "Settings3", "Settings4"}
}
};
}
}
Option 2
Create an object to wrap your Channel objects, and put in it the logic to allow one combobox to drive the items of the other:
public class ChannelWrapper : INotifyPropertyChanged
{
#region INotifyPropertyChanged values
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private object comboBox1SelectedItem;
public object ComboBox1SelectedItem
{
get { return this.comboBox1SelectedItem; }
set
{
if (this.comboBox1SelectedItem != value)
{
this.comboBox1SelectedItem = value;
this.OnPropertyChanged("ComboBox1SelectedItem");
// Put the logic to change the items available in the second combobox here
if (value == "Value1")
this.ComboBox2ItemsSource = new List<object>() { "Setting1", "Setting2" };
if (value == "Value2")
this.ComboBox2ItemsSource = new List<object>() { "Setting3", "Setting4" };
}
}
}
private List<object> comboBox2ItemsSource;
public List<object> ComboBox2ItemsSource
{
get { return this.comboBox2ItemsSource; }
set
{
if (this.comboBox2ItemsSource != value)
{
this.comboBox2ItemsSource = value;
this.OnPropertyChanged("ComboBox2ItemsSource");
}
}
}
public Channel Ch { get; set; }
}
Your Root class would then expose a collection of wrappers instead a collection of channels. Your DataGrid would have 2 ComboBoxColumns. The SelectedItem of the first would be bound to the property "ComboBox1SelectedItem" of the wrapper. The ItemsSource of the second would be bound to the property "ComboBox2ItemsSource" of the wrapper and the SelectedItem of the second column would be bound the setting of the Channel instance of the wrapper, with the path "Ch.TheSettting".