I have a DataGrid
where the SelectedItem
is bound to a VM Selected property. I have a search control that will do a find and the SelectedItem
You need to give the newly selected row logical focus. After selecting the new item try replacing your SetFocus
call with this:
var selectedRow = (DataGridRow)dataGrid1.ItemContainerGenerator.ContainerFromIndex(dataGrid1.SelectedIndex);
FocusManager.SetIsFocusScope(selectedRow, true);
FocusManager.SetFocusedElement(selectedRow, selectedRow);
This PowerShell snippet worked for me:
$dataGrid = ...
$dataGrid.add_GotKeyboardFocus({
param($Sender,$EventArgs)
if ($EventArgs.OldFocus -isnot [System.Windows.Controls.DataGridCell) {
$row = $dataGrid.ItemContainerGenerator.ContainerFromIndex($dataGrid.SelectedIndex)
$row.MoveFocus((New-Object System.Windows.Input.TraversalRequest("Next")))
}
})
The FocusManager solution didn't work for me for some reason. Also I required a more general apporach. So here is, what I came up with:
using System.Windows.Controls;
public static void RestoreFocus(this DataGrid dataGrid,
int column = 0, bool scrollIntoView = false)
{
if (dataGrid.IsKeyboardFocusWithin && dataGrid.SelectedItem != null)
{
// make sure everything is up to date
dataGrid.UpdateLayout();
if (scrollIntoView)
{
dataGrid.ScrollIntoView(dataGrid.SelectedItem);
}
var cellcontent = dataGrid.Columns[column].GetCellContent(dataGrid.SelectedItem);
var cell = cellcontent?.Parent as DataGridCell;
if (cell != null)
{
cell.Focus();
}
}
}
And call it like this:
MyDataGrid.IsKeyboardFocusWithinChanged += (sender, e) =>
{
if ((bool)e.NewValue == true)
{
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Loaded, new Action(() =>
{
MyDataGrid.RestoreFocus(scrollIntoView: true);
}));
}
};