Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Focus on DataGridCell for SelectedItem when DataGrid Receives Keyboard Focus

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 of the DataGrid changes (and scrolls into view). WPF 4.0 and DataGrid SelectionUnit="FullRow".

My problem is with the focus. The DataGrid receives focus (via attached property / binding) but you can't use the Up, Down, Page Up, Page Down keys to change rows (SelectedItem). If I tab again, the first cell of the first row displayed is selected which changes the SelectedItem.

Bottom line, how can I give keyboard focus to the DataGridCell for the SelectedItem when the DataGrid receives focus?

There are so many DataGrid / Focus questions and tried a few things already. Thanks for your help.

like image 208
KornMuffin Avatar asked Jun 14 '13 21:06

KornMuffin


2 Answers

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);
like image 135
Richard E Avatar answered Oct 23 '22 20:10

Richard E


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);
        }));
    }
};
like image 1
Tim Pohlmann Avatar answered Oct 23 '22 19:10

Tim Pohlmann