Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Datagrid Set focus on newly added row

Tags:

wpf

I have a datagrid bound to an observable collection. When the user press the "add button" it adds a new row and I do this by adding a new element to the observablecollection.

I cannot figure out how to make the newly added row with the first cell in focus as if we were editing. I am using a MVVM pattern.

Any ideas or suggestions?

like image 870
user9969 Avatar asked Jul 22 '10 10:07

user9969


2 Answers

The answer given by Gauss is the right approach, but with some code, it is clearer:

void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Loaded += Row_Loaded;
}

void Row_Loaded(object sender, RoutedEventArgs e)
{        
    var row = (DataGridRow) sender;
    row.Loaded -= Row_Loaded;
    DataGridCell cell = GetCell(dataGrid, row, 0);
    if (cell != null) cell.Focus();
    dataGrid.BeginEdit();        
}

static DataGridCell GetCell(DataGrid dataGrid, DataGridRow row, int column)
{
    if (dataGrid == null) throw new ArgumentNullException("dataGrid");
    if (row == null) throw new ArgumentNullException("row");
    if (column < 0) throw new ArgumentOutOfRangeException("column");

    DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
    if (presenter == null)
    {
        row.ApplyTemplate();
        presenter = FindVisualChild<DataGridCellsPresenter>(row);
    }
    if (presenter != null)
    {
        var cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
        if (cell == null)
        {
            dataGrid.ScrollIntoView(row, dataGrid.Columns[column]);
            cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
        }
        return cell;
    }
    return null;
}

static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        var visualChild = child as T;
        if (visualChild != null)
            return visualChild;
        var childOfChild = FindVisualChild<T>(child);
        if (childOfChild != null)
            return childOfChild;
    }
    return null;
}

You retrieve the row in the DataGrid.LoadingRow event, but the cell is not yet available. So you put an handler on the Loaded event in order to wait for this event to occur and then you can retrieve the cell and put the focus on it.

The handler is removed to avoid a new triggering.

The editing session can also be started with dataGrid.BeginEdit().

All of this is in the code-behind, because it belongs to the view.

like image 138
Maxence Avatar answered Oct 20 '22 18:10

Maxence


Try capturing the DataGrid's LoadingRow (or similar) event. Do a SetFocus(e.Row) (or similar) on the row. This is purely View-oriented, so it conforms to MVVM.

like image 26
Jake Berger Avatar answered Oct 20 '22 19:10

Jake Berger