I have an item control that will populate datagrids with data from an ObservableCollection TrayTypesDataGrids
private ObservableCollection<TrayTypeDataGrid> trayTypesDataGrids;
public class TrayTypeDataGrid : ViewModelBase
{
private ObservableCollection<TrayType> trayTypes;
public ObservableCollection<TrayType> TrayTypes
{
get => trayTypes;
set
{
trayTypes = value;
OnPropertyChanged(nameof(TrayTypes));
}
}
private ICommand selectionChangedCommand;
public ICommand SelectionChangedCommand
{
get
{
return selectionChangedCommand ?? (selectionChangedCommand = new CommandHandler((param) => SelectionChanged(param), true));
}
}
public TrayTypeDataGrid(ObservableCollection<TrayType> trayTypes)
{
this.trayTypes = trayTypes;
}
private void SelectionChanged(object args)
{
TrayType SelectedTrayType = ((TrayType)((SelectionChangedEventArgs)args).AddedItems[0]);
}
}
<ItemsControl x:Name="DataGridControl" ItemsSource="{Binding TrayTypesDataGrids}" HorizontalAlignment="Center" DockPanel.Dock="Top">
<ItemsControl.Template>
<ControlTemplate>
<DockPanel IsItemsHost="True" Height="{Binding Path=ActualHeight, ElementName=DataGridControl}"/>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataGrid Style="{StaticResource DataGridStyleDetails}" ItemsSource="{Binding TrayTypes}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" ElementStyle="{StaticResource TBColumn}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" ElementStyle="{StaticResource TBColumn}"/>
<DataGridTextColumn Header="D" Binding="{Binding D}" ElementStyle="{StaticResource TBColumn}"/>
<DataGridTextColumn Header="W" Binding="{Binding W}" ElementStyle="{StaticResource TBColumn}"/>
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged" >
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This works and all the DataGrids are populated correctly and the SelectionChanged gets the row in the TrayTypeDataGrid class. However, I want to capture when the selection changes and also select the matching row on each of the DataGrids from the ItemControl. How can I access those Datagrids from the ItemControl and set their selected row or maybe change the background of the matchin rows?
I don't think this is possible to do in an MVVM, is that right?
The main challenge here is that WPF
MultiSelector's (from whichDataGridinherits)SelectedItemsproperty is not aDependencyProperty. This makes it impossible to bind directly.There are many hacks out there for circumventing this. This question has several answers that will lead you in the right direction, but none of them offers a complete solution that I would endorse, so I would not simply declare this a duplicate:
Bind to SelectedItems from DataGrid or ListBox in MVVM
Brian Hinchey's answer - which subclasses
DataGridand adds anew SelectedItemsproperty, is I think the closest, but is not complete because it doesn't allow setting the selection through binding (only retrieving it). To handle setting you'll need to handle a property change via a callback toPropertyMetadatawhen declaring the newSelectedItemsDP, like so:(You also need to ensure that your DP change handler doesn't get executed during the
OnSelectionChangedhandler, which is fired by a UI-induced selection change, hence the_isUISelectionChangePendingtrick).If you can get this far, then things become simpler: bind each
MyNewDataGridClass(two-way) to anIList SelectedItemsproperty on your view model. If you set it all up correctly, a UI-induced selection change on any grid will propagate to your view model property and then back out to the other grids.