I had to solve the issue in a different way than the jl.'s answer, because it could not do any processing before (e.g. checking access) deletion happen as a Command could. While perhaps not as robust, it does exactly what you asked about. Keeping your original code unchanged, just hook the following SelectionChanged, or even better use attached property.
Because deleting an item first produces SelectionChanged with index -1 it is easy enough to reliably guess when deletion happen and set a flag. After the first invocation with -1 another one with nearest neighbor index happens, at this point if the flag was set, it is safe to focus the current cell:
private int LastItemCount = 0;
private bool ShouldFocusOnSelection = false;
private void FocusOnDeleteDG_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is DataGrid dg)
{
if (IsRemovalEvent(dg, e))
{
ShouldFocusOnSelection = true;
}
else if (ShouldFocusOnSelection)
{
dg.FocusCurrentCell();
ShouldFocusOnSelection = false;
}
LastItemCount = dg.Items.Count;
}
}
where IsRemovalEvent checks if the selection event was produced by item removal:
private static bool IsRemovalEvent(DataGrid dg, SelectionChangedEventArgs e)
{
return e.RemovedItems.Count > 0
&& e.AddedItems.Count == 0
&& dg.SelectedIndex == -1
&& dg.Items.Count > 0
&& LastItemCount > dg.Items.Count;
}
and the FocusCurrentCell/GetChildren are helper methods you probably already have:
public static void FocusCurrentCell(this DataGrid dataGrid)
{
var rowIndex = dataGrid.SelectedIndex != -1 ? dataGrid.SelectedIndex : (dataGrid.Items.Count > 0 ? 0 : -1);
if (!(dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex) is DataGridRow row))
{
return;
}
if (dataGrid.CurrentColumn?.DisplayIndex != null)
{
// traverse VisualTree using VisualTreeHelper.GetChild()
var cell = row.GetChildren<DataGridCell>()
.Skip(dataGrid.CurrentColumn.DisplayIndex).FirstOrDefault();
Keyboard.Focus(cell);
}
}