In a DataGrid, I want a ComboBoxColumn that has the same content for each row. The content of the ComboBox is dynamic: if you select a value in the ComboBox for a row, this selected value must not be selectable for the other rows. My current problem is that the content of the ComboBox is not updated in the previous lines. I made a simple example to explain it:
XAML
<StackPanel>
<DataGrid ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
Height="auto"
CanUserAddRows="False"
AutoGenerateColumns="False"
IsReadOnly="False">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="Key" MinWidth="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.KeyList, RelativeSource={RelativeSource Findancestor, AncestorType={x:Type Window}}}"
SelectedItem="{Binding SelectedKey, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled" Value="{Binding IsSelectable}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Value" Binding="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
<Button Margin="0,10,0,0" Width="80" Content="Add Row" Command="{Binding AddRowCommand}"/>
</StackPanel>
MAIN VM
public class MainVM
{
private ObservableCollection<ItemsVM> myItems;
private List<Key> myKeyList = new List<Key>()
{
new Key("Item 1", true),
new Key("Item 2", true),
new Key("Item 3", true)
};
public MainVM()
{
myItems = new ObservableCollection<ItemsVM>();
AddRowCommandAction();
}
public ObservableCollection<ItemsVM> Items => myItems;
public ItemsVM SelectedItem { get; set; }
public List<Key> KeyList => myKeyList;
private void SetKeySelectability()
{
foreach (Key item in myKeyList)
{
if (myItems.Any(x => x.SelectedKey == item))
item.IsSelectable = false;
else
item.IsSelectable = true;
}
}
private RelayCommand myAddRowCommand;
public RelayCommand AddRowCommand
{
get
{
if (myAddRowCommand == null)
myAddRowCommand = new RelayCommand(AddRowCommandAction);
return myAddRowCommand;
}
}
private void AddRowCommandAction()
{
myItems.Add(new ItemsVM
{
Value = string.Format("Row {0}", myItems.Count + 1),
SelectedKey = myKeyList.FirstOrDefault(x => x.IsSelectable == true)
});
SetKeySelectability();
}
}
OTHER CLASSES
public class ItemsVM
{
public string Value { get; set; }
public Key SelectedKey { get; set; }
}
public class Key : ObservableObject
{
private bool _IsSelectable;
public Key(string name, bool isselectable)
{
Name = name;
IsSelectable = isselectable;
}
public string Name { get; set; }
public bool IsSelectable
{
get { return _IsSelectable; }
set
{
if (_IsSelectable == value) return;
_IsSelectable = value;
OnPropertyChanged(nameof(IsSelectable));
}
}
}
At start, we can see as the Item 1 is selected for the Row 1, Item 1 IsSelectable property is updated and is not selectable anymore:
After cliked the Button to add a row, I get this (which is correct). The two used values are not selectable and the Row 1's ComboBox has the same value.
Now, I change the value for the Row 1: We can see that the Item 1 is not selectable (but it should be) and the Row 2's ComboBox is not up to date either (Item 3 is selectable and should not and Item 1 is not released)
How can I achieve this?




If I understand correctly, in order to achieve this, you need to update the IsSelectable property of the Key instances when a ComboBox's selected item changes.
In your case, you need to raise the PropertyChanged event from your ItemsVM class whenever SelectedKey changes. This is needed to notify the MainVM so it can update the IsSelectable properties of the Key instances.
Here is how you can do it: