I have this classes
public class UILanguagesModel : INotifyPropertyChanged
{
public UILanguagesModel()
{
IList<UILanguage> list = new List<UILanguage>();
UILanguage english = new UILanguage();
english.Culture = "en";
english.SpecCulture = "en-US";
english.EnglishName = "English";
UILanguage spanish = new UILanguage();
spanish.Culture = "es";
spanish.SpecCulture = "es-ES";
spanish.EnglishName = "Spanish";
list.Add(english);
list.Add(spanish);
_languages = new CollectionView(list);
}
private readonly CollectionView _languages;
private UILanguage _language;
public CollectionView Languages
{
get { return _languages; }
}
public UILanguage Language
{
get { return _language; }
set
{
if (_language == value) return;
_language = value;
OnPropertyChanged("Language");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public sealed class UILanguage
{
public string EnglishName { set; get; }
public string Culture { set; get; }
public string SpecCulture { set; get; }
}
And I need to populate with "EnglisgName" WPF Combobox.
How to do it?
Thank you!
Markup XAML
<ComboBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Margin="0,1,0,0"
Name="cmbLanguages" VerticalAlignment="Top" Width="207" />
When binding a ComboBox to a collection of items you would usually define your collection class as an ObservableCollection:
public class UILanguages : ObservableCollection<UILanguage>
{
}
and bind your ComboBox to a CollectionViewSource that uses the ObservableCollection as Source, like declared in the following XAML. CollectonViewSource keeps tracks of the selected item.
<Window x:Class="ComboBoxTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ComboBoxTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:UILanguages x:Key="UILanguages"/>
<CollectionViewSource x:Key="UILanguagesViewSource" Source="{StaticResource UILanguages}"/>
</Window.Resources>
<Grid>
<ComboBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Margin="0,1,0,0"
Name="cmbLanguages" VerticalAlignment="Top" Width="207"
ItemsSource="{Binding Source={StaticResource UILanguagesViewSource}}"/>
</Grid>
</Window>
Then populate the collection:
UILanguages languages = (UILanguages)Resources["UILanguages"];
languages.Add(
new UILanguage
{
Culture = "en",
SpecCulture = "en-US",
EnglishName = "English"
});
languages.Add(
new UILanguage
{
Culture = "es",
SpecCulture = "es-ES",
EnglishName = "Spanish"
});
It is of course also possible to define the ObservableCollection and the CollectionViewSource in code, thus avoiding the XAML resource declarations:
UILanguages languages = new UILanguages();
languages.Add(
new UILanguage
{
Culture = "en",
SpecCulture = "en-US",
EnglishName = "English"
});
languages.Add(
new UILanguage
{
Culture = "es",
SpecCulture = "es-ES",
EnglishName = "Spanish"
});
CollectionViewSource cvs = new CollectionViewSource
{
Source = languages
};
cmbLanguages.SetBinding(ItemsControl.ItemsSourceProperty, new Binding { Source = cvs });
You may also want to override ToString in your UILanguage class to display something useful:
public sealed class UILanguage
{
public string EnglishName { set; get; }
public string Culture { set; get; }
public string SpecCulture { set; get; }
public override string ToString()
{
return EnglishName;
}
}
If in the constructor of the View (the C# file associated with your XAML), you set:
this.DataContext = new UILanguagesModel ();
Then it's as simple as a Binding:
<ComboBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Margin="0,1,0,0"
Name="cmbLanguages" VerticalAlignment="Top" Width="207"
ItemsSource="{Binding Languages}"/>
Then you're probably going to want the selected value of your ComboBox to be in your Language property, in which case the binding becomes:
<ComboBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Margin="0,1,0,0"
Name="cmbLanguages" VerticalAlignment="Top" Width="207"
ItemsSource="{Binding Languages}"
SelectedValue="{Binding Language}"/>
EDIT: You're probably going to have to declare your Languages collection as an ObservableCollection
Related
Recently I started converting a proof of concept UWP app to a working WPF app.
What I want is to have two dropdowns (combobox) of "characters" I can choose, I want them databound to an ObservableCollection property, where the characters I selected is stored in a different Character property for player 1 then player 2.
I had databinding on dropdowns working in the UWP app, but I can't get it to work in the WPF app.
In the WPF app, the comboboxes stay empty and I can't select an option.
I tried following the answer to this question, but I think I'm missing something: Binding a WPF ComboBox to a custom list
Here is the code, kept minimal:
Character.cs
public class Character : INotifyPropertyChanged
{
private int _id;
public int Id
{
get
{
return _id;
}
set
{
_id = value;
}
}
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public Character(int id, string name)
{
Id = id;
Name = name;
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindow.xaml
<Window x:Class="SmashWiiUOverlayManager.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:SmashWiiUOverlayManager"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0">
<ComboBox
Name="Player1CharacterDropdown"
ItemsSource="{Binding CharacterList, Mode=TwoWay}"
SelectedItem="{Binding Player1SelectedCharacter, Mode=TwoWay}"
SelectedValuePath="Name"
DisplayMemberPath="Name"
Width="144">
</ComboBox>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right">
<ComboBox
Name="Player2CharacterDropdown"
ItemsSource="{Binding CharacterList, Mode=TwoWay}"
SelectedItem="{Binding Player2SelectedCharacter, Mode=TwoWay}"
SelectedValuePath="Character"
DisplayMemberPath="Name"
Width="144">
</ComboBox>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<Character> _characterList;
public ObservableCollection<Character> CharacterList
{
get
{
return _characterList;
}
set
{
_characterList = value;
}
}
private Character _player1SelectedCharacter;
public Character Player1SelectedCharacter
{
get
{
return _player1SelectedCharacter;
}
set
{
_player1SelectedCharacter = value;
}
}
private Character _player2SelectedCharacter;
public Character Player2SelectedCharacter
{
get
{
return _player2SelectedCharacter;
}
set
{
_player2SelectedCharacter = value;
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
CharacterList = new ObservableCollection<Character>
{
new Character(0, "Mario"),
new Character(1, "Luigi"),
new Character(2, "Wario"),
};
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
This code currently leaves the comboboxes empty.
When I use:
Player1CharacterDropdown.ItemsSource = new ObservableCollection<Character>
{
new Character(0, "Mario", ".\\images\\mario.png"),
new Character(1, "Luigi", ".\\images\\luigi.png"),
new Character(2, "Wario", ".\\images\\wario.png"),
};
... the combox gets filled, but it's databound to the property, which is what I would like.
What am I missing here?
I have met following problem in WPF binding.
I need to load objects from XML file and create list of loaded items in listbox, and when listbox item is selected then display suitable set of objects.
I can do it in 'code behind' style, but I really want to do it in proper MVVM way.
My Matrixes class is generated by xsd2code from which contains:
List<CorrectionMatrixType> correctionMatrixField;
and follows
public partial class CorrectionMatrixType {
public MatrixType A {get; set;}
public MatrixType B {get; set;}
public MatrixType C {get; set;}
... }
How can I create 'dynamically'something like Grid with three DataGrids by Viewmodel and bind each matrix (A,B,C) to them which content will change depends of value selected in listbox? I know that to bind my MatrixType to DataGrid i have to use ValueConverter to convert my object to two-dimensional array.
Maybe I have to admit I am using MVVM Light.
Please, any suggestions?
I would use the INotifyPropertyChanged Interface. Here is a small example (not exactly your case, but enough to show the principle, I think):
MatrixType class:
public class MatrixType
{
public string Name { get; set; }
public string Width { get; set; }
public string Height { get; set; }
}
Xaml:
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" ItemsSource="{Binding Items}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedItem}"></ListBox>
<Grid Grid.Column="1">
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding SelectedItem.Name}" Height="30"/>
<TextBox Text="{Binding SelectedItem.Height}" Height="30"/>
<TextBox Text="{Binding SelectedItem.Width}" Height="30"/>
</StackPanel>
</Grid>
</Grid>
MainViewModel.cs:
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
var list = new List<MatrixType>
{
new MatrixType {Height = "233", Name = "A", Width = "133"},
new MatrixType {Height = "333", Name = "B", Width = "233"},
new MatrixType {Height = "433", Name = "C", Width = "333"}
};
Items = new ObservableCollection<MatrixType>(list);
}
private MatrixType _selectedItem;
public MatrixType SelectedItem
{
get => _selectedItem;
set { _selectedItem = value; OnPropertyChanged(); }
}
public ObservableCollection<MatrixType> Items { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainViewModel.cs (when using MVVM Light):
public class MainViewModel : ObservableObject
{
public MainViewModel()
{
var list = new List<MatrixType>
{
new MatrixType {Height = "233", Name = "A", Width = "133"},
new MatrixType {Height = "333", Name = "B", Width = "233"},
new MatrixType {Height = "433", Name = "C", Width = "333"}
};
Items = new ObservableCollection<MatrixType>(list);
}
private MatrixType _selectedItem;
public MatrixType SelectedItem
{
get => _selectedItem;
set { _selectedItem = value; RaisePropertyChanged(); }
}
public ObservableCollection<MatrixType> Items { get; set; }
}
I wrote solution by myself, I don't know if it is good MVVM solution.
I re-write my XSD so MatrixType becomes SimpleMatrix, and now:
XAML:
<ListBox Margin="5,20,0,5" ItemsSource="{Binding CorrectionMatrixes}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<command:EventToCommand Command="{Binding SelectionChangedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="Loaded">
<command:EventToCommand Command="{Binding ListBoxLoadedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
<DataGrid CanUserAddRows="False" HeadersVisibility="None" ItemsSource="{Binding CorrectionMatrixA, Converter={StaticResource MatrixToArray }}"/>
And in my viewmodel:
public RelayCommand<SelectionChangedEventArgs> SelectionChangedCommand => new RelayCommand<SelectionChangedEventArgs>(SelectionChanged);
public RelayCommand<RoutedEventArgs> ListBoxLoadedCommand => new RelayCommand<RoutedEventArgs>(ListBoxLoaded);
private string CorrectionMatrixName { get; set; }
private void ListBoxLoaded(RoutedEventArgs obj)
{
if (obj.Source is ListBox listBox)
{
listBox.SelectedIndex = 0;
}
}
private void SelectionChanged(SelectionChangedEventArgs obj)
{
if (obj.AddedItems.Count <= 0) return;
if (obj.AddedItems[0] is CorrectionMatrix matrix)
{
CorrectionMatrixName = matrix.name;
}
RaisePropertyChanged(() => CorrectionMatrixA);
}
public SimpleMatrix CorrectionMatrixA
{
get
{
try
{
var x = Matrixes.Correction.Where(a => a.name == CorrectionMatrixName)
.Select(a => a.A).Single();
return x;
}
catch (InvalidOperationException)
{
return null;
}
}
}
Matrixes are loaded by:
Matrixes = settingsLoader.LoadMatrixes(Properties.Resources.MatrixesSettings);
How does it all works:
when user control is loaded => selected index on listbox is setting to zero
When selected item on listbox is changed it fires event that changes CorrectionMatrixName
Binding properties returns suitable matrix finding it in array by name
I don't post Converter code - it doesn't matter here.
Thats full, my own solution that worked for me. I hope it will helps other people
I'm working on a C#/WPF application.
I'm invoking ProcessServiceResponse() method in MainViewModel on click of a button.
SelectedCountry property value is correctly getting set in this method.The country list combobox is also showing the list of countries.
But somehow, am not seeing a selected value(for e.g. SG) in the country dropdown list.
Any ideas as to what am I missing here please?
Let me know if you need any other details around the code.
Thanks.
Here's my code.
MainWindow View:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:MainViewModel="clr-namespace:MyTool.ViewModels"
xmlns:ViewModel="clr-namespace:MyTool.ViewModel.Bonds"
xmlns:View="clr-namespace:MyTool" x:Class="MyTool.MainWindow"
Title="{Binding DisplayName, Mode=OneWay}" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen" Height="600" Width="1100">
<Window.DataContext>
<MainViewModel:MainWindowViewModel/>
</Window.DataContext>
<ComboBox Margin="1,0" ItemsSource="{Binding MyViewModel.CountryList,UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Description" SelectedValuePath="Code" SelectedItem="{Binding MyViewModel.SelectedCountry, Mode=TwoWay}" TabIndex="2" Grid.Row="7" Grid.Column="2" HorizontalAlignment="Left" Height="23" VerticalAlignment="Top" Width="180" />
MainViewModel:
public MainWindowViewModel()
{
MyAttributes = new MyViewModel();
}
public object MyAttributes
{
get { return m_myViewModel; }
set
{
m_myViewModel = value;
OnPropertyChanged("MyAttributes");
}
}
public void ProcessServiceResponse()
{
var destination = new MyViewModel();/
Type destinationType = destination.GetType();
PropertyInfo[] destinationTypePI = destinationType.GetProperties();
string propertyName = string.Empty;
object propertyValue = null;
foreach (var pinfo in sourcePI)
{
propertyName = pinfo.Name.Trim();
var matchingItem = destinationTypePI.ToList().Where(d => d.Name == propertyName);
if (matchingItem != null && matchingItem.Count() > 0)
{
propertyValue = pinfo.GetValue(serviceResponse.lst_DKSecurities[0]);
matchingItem.FirstOrDefault().SetValue(destination, propertyValue);
}
}
this.MyAttributes = destination;
}
MyViewModel:
namespace MyTool.ViewModels;
public class MyViewModel
{
public MyViewModel
{
this.CountryList = GetCountryList();
}
public string SelectedCountry
{
get
{
return m_selectedCountry;
}
set
{
m_selectedCountry = value;
}
}
}
After you fill the CountryList, assign to the SelectedCountry the list item you want to display:
CountryList = new ObservableCollection<string> {"A", "B", "C"};
SelectedCountry = CountryList[0];
<ComboBox ItemsSource="{Binding CountryList, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedCountry, Mode=TwoWay}" />
I'm trying to build a DTO to store the software configuration, but I'm stuck because my view is not sending the data to my ViewModel and also to my DTO.
I need to transfer 2 textbox and 3 combobox to my DTO, but using this code the values are always empty.
My ViewModel:
public class ViewModelProcessamentoArquivo : ViewModelBase
{
private PesquisaConfiguracao pesquisaConfiguracao;
public PesquisaConfiguracao PesquisaConfiguracao
{
get { return pesquisaConfiguracao; }
set
{
pesquisaConfiguracao = value;
base.OnPropertyChanged("PesquisaConfiguracao");
}
}
}
My DTO/Model
public class PesquisaConfiguracao
{
public string ArquivoOrigem { get; set; }
public string ArquivoDestino { get; set; }
public string TipoPesquisa { get; set; }
public string PesquisaVeicular { get; set; }
public string PesquisaCrediticia { get; set; }
}
And my View is like this.
<TextBox Name="txtBuscarArquivoOrigem" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Height="30" Margin="10, 0" Text="{Binding PesquisaConfiguracao.ArquivoOrigem}" />
<TextBox x:Name="txtBuscarArquivoDestino" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3" Height="30" Margin="10, 0" Text="{Binding PesquisaConfiguracao.ArquivoDestino}" IsEnabled="false" />
...
Do you guys know why it's happening? I've used something similar in my other project and worked just fine. Also if you have any other possibly way to fix this issue, please comment!
First UpdateSourceTrigger PropertyChanged, that way the target (view) will update your source object on every change:
<TextBox Name="txtBuscarArquivoOrigem" Height="30" Text="{Binding PesquisaConfiguracao.ArquivoOrigem, UpdateSourceTrigger=PropertyChanged}" />
Then implement in your source object the INotifyPropertyChange Interface on it's properties in order to update the view when the value has changed:
private string _arquivoOrigem;
public string ArquivoOrigem
{
get
{
return _arquivoOrigem;
}
set
{
_arquivoOrigem = value;
OnPropertyChanged("ArquivoOrigem");
}
}
Put a BreakPoint in the property setter and it will break there when you change the value in the view TextBox.
If it doesn't work for you probably forgot to set your DataContext to your ViewModel:
<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
DataContext="{StaticResource MainViewModel}">
Or did not initialize your source object:
public MainViewModel()
{
pesquisaConfiguracao = new PesquisaConfiguracao
{
ArquivoDestino = "aaa",
ArquivoOrigem = "bbb",
PesquisaCrediticia = "ccc",
PesquisaVeicular = "dddd",
TipoPesquisa = "eee"
};
}
I have a datagrid with 2 DataGridComboxClolumn elements and want to change the ItemsSource of the second when the value of the first is changed. How can I set up such a binding?
Note: the datagrid has it's own itemssource and the data is hierachical following:
ItemsSource of the datagrid (list op type Channel):
public class Root
{
public List<Channel> Ch { get; set; } // This is the ItemsSource of the datagrid itself
}
public class Channel
{
public Settings TheSettings { get; set; }
}
The thing I want to accomplish is that the TheSettings is set with selected value of the second ComboBox. This is easyly done by setting the ComboBox ItemsSource. Although I require that the ItemsSource of the second combox to be dynamic. E.g. it has to change to the source selected in the FIRST combobox. How can this be done?
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".