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);
}
}