Focus on DataGridCell for SelectedItem when DataGr

2019-02-05 06:00发布

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.

3条回答
放荡不羁爱自由
2楼-- · 2019-02-05 06:13

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")))
    }
})
查看更多
混吃等死
3楼-- · 2019-02-05 06:21

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);
查看更多
甜甜的少女心
4楼-- · 2019-02-05 06:32

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);
        }));
    }
};
查看更多
登录 后发表回答