Datagrid Set focus to newly added row

I have a datagrid associated with an observable collection. When the user clicks the add button, he adds a new row, and I do this by adding a new element to the observed collections.

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

Any ideas or suggestions?

+7
wpf
source share
6 answers

Try to capture the DataGrid LoadingRow event (or the like). Make SetFocus(e.Row) (or similar) in the line. It is purely view-oriented, so it complies with MVVM.

+1
source share

Gauss's answer is the correct 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 a handler in the Loaded event to wait for this event to occur, and then you can get the cell and direct it to it.

The handler is deleted to avoid a new start.

An edit session can also be started using dataGrid.BeginEdit() .

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

+1
source share

You want to do something like this:

 DataGridCell cell = GetCell(rowIndex, colIndex); cell.Focus; 

Of course you need this elusive GetCell () method. Vincent Sibal of MSFT wrote this method (and the necessary GetRow) in this forum post . I was looking for something else when I came across this, so I did not use it, but others seemed lucky with it. You will notice that there are links to his blog , which may also be useful for all things related to DataGrid.

0
source share


Hopes to help others.
I will show the MVVM path in the view:

 <DataGrid Name="dg1" ItemsSource="{Binding Table}" AutoGenerateColumns="False" Margin="3" SelectionMode="Single" IsReadOnly="True" SelectedIndex="{Binding Path=SelectedIndex, Mode=TwoWay}"> <DataGrid.Columns> <DataGridTextColumn Header="Date" Binding="{Binding mydate}" MinWidth="100"></DataGridTextColumn> <DataGridTextColumn Header="Count" Binding="{Binding Count}" MinWidth="100"></DataGridTextColumn> </DataGrid.Columns> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged" SourceName="dg1" > <i:InvokeCommandAction Command="{Binding DgSelectionChanged}" CommandParameter="{Binding ElementName=dg1}"/> </i:EventTrigger> </i:Interaction.Triggers> </DataGrid> 

now in the View-Model:
you need to install SelectedIndex after: add, remove, etc ... and

  private ICommand dgSelectionChanged; /// <summary> /// when the datagrid Selection Changes /// </summary> public ICommand DgSelectionChanged { get { return dgSelectionChanged ?? (dgSelectionChanged = new RelayCommand<DataGrid>(dg1 => { // whatever you want when the Selection Changes SelectedIndex= d //select the item if (dg1.SelectedIndex > -1) { dg1.Focus(); dg1.CurrentCell = new DataGridCellInfo(dg1.Items[dg1.SelectedIndex], dg1.Columns[0]); } })); } } 

by the way, to select the first line after loading the control, add this to the view:

  <!-- select the row after control loaded --> <i:EventTrigger EventName="Loaded" SourceName="dg1" > <i:InvokeCommandAction Command="{Binding DgSelectionChanged}" CommandParameter="{Binding ElementName=dg1}"/> </i:EventTrigger> </i:Interaction.Triggers> 

thanks Avi.

0
source share

The combination of LoadingRow , e.Row.Loaded and the GetCell() method of the following link worked for me:

http://social.technet.microsoft.com/wiki/contents/articles/21202.wpf-programmatically-selecting-and-focusing-a-row-or-cell-in-a-datagrid.aspx

The DataGrid.LoadingRow event is raised before the cell is accessible through GetCell . But in the DaraGridRow.Loaded event DaraGridRow.Loaded cell is available.

After that, you can use cell.Focus() and DataGrid.BeginEdit() .

0
source share

Solved this in my case thanks to Jake Berger's answer.

Binding a DataGrid SelectedItem and handling the LoadingRow event works just fine.

eg:

 <DataGrid SelectionUnit="FullRow" SelectionMode="Single" ItemsSource="{Binding Source=MyList}" SelectedItem="{Binding SelectedDataItem, Mode=TwoWay}" LoadingRow="MyDataGrid_LoadingRow"></DataGrid> 
 private void ServerContentsListing_LoadingRow(object sender, DataGridRowEventArgs e) { SelectedDataItem = (MyDataObject)e.Row.Item; } 
0
source share

All Articles