How to programmatically select AND focus a cell in the new WPF Datagrid
-
Friday, August 22, 2008 11:37 PM
It's easy to select and focus a ListViewItem within a WPF ListView using the following code:
...
myListView.SelectedItem = myListView.Items[index];
myListView.ScrollIntoView(myListView.Items[index]);
ListViewItem listViewItem = myListView.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
listViewItem.Focus();
...
How would you do exactly the same for the new WPF DataGrid, i.e. programmatically select a cell within the WPF DataGrid and then programmatically put the focus on that cell, so that you can then navigate through the DataGrid with the arrow keys on the keyboard? Part of the code for selecting would be:...
myDataGrid.SelectedItem = myDataGrid.Items[index];
myDataGrid.ScrollIntoView(myDataGrid.Items[index]);
...
However, what is the code for putting the focus on the selected WPF DataGrid Cell? Thanks for any help!
All Replies
-
Saturday, August 23, 2008 12:31 AM
Here is one way to set focus to a particular cell programmatically:
DataGridCell cell = GetCell(rowIndex, colIndex);
cell.Focus;
See, http://forums.msdn.microsoft.com/en-US/wpf/thread/63974f4f-d9ee-45af-8499-42f29cbc22ae for the implementation of GetCell().- Marked As Answer by anbri Saturday, August 23, 2008 1:04 AM
-
Saturday, August 23, 2008 1:04 AM
Oh Great! Vincent, thank you very much for this solution that will also be helpful in other situations.
Meanwhile, I also found another way to set the focus. Perhaps this is also helpful for somebody else:
...
int index = 11;
myDataGrid.SelectedItem = myDataGrid.Items[index];
myDataGrid.ScrollIntoView(myDataGrid.Items[index]);
DataGridRow dgrow = (DataGridRow)myDataGrid.ItemContainerGenerator.ContainerFromItem(myDataGrid.Items[index]);
dgrow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
... -
Monday, May 11, 2009 11:43 AMIn one approach like it I must select and highlight the row in DataGrid.
It doesn't function with dgrow.MoveFocus, but functions well with dgrow.IsSelected=True.
But if any other rows where selected before, they stay selected.
if you want to have only one row selected, you must do something like:- foreach (object _rowitem in MyDataGrid.Items) {
- DataGridRow _visualItem = (DataGridRow)MyDataGrid.ItemContainerGenerator.ContainerFromItem(_rowitem);
- _visualItem.IsSelected = false;
In the case ItemContainerGenerator.Status=NotStarted.
For example, you create a new datagrid. It is not generated after InitializeComponent(), but only after DataGrid.Loaded event.
Then you can call your selection routine in or after DataGrid.Loaded. -
Thursday, June 04, 2009 2:51 PMI would like to navigate between the GridView Cells using directional keys. when user clicks on a cell and press the arrow keys then the focus has to be moved on to the next cell. I could find the Coordinates of the next cell, now with this coordinates I would like to set focus on that cell. Please help me with the code.
-
Tuesday, August 25, 2009 4:02 AM
I haven't had much luck the other ways, so i use this workaround
//first focus the grid grid.Focus(); //then create a new cell info, with the item we wish to edit and the column number of the cell we want in edit mode DataGridCellInfo cellInfo = new DataGridCellInfo(itemToSelect, grid.Columns[0]); //set the cell to be the active one grid.CurrentCell = cellInfo; //scroll the item into view grid.ScrollIntoView(itemToSelect); //begin the edit grid.BeginEdit();
this works for me. (it would make a nice little static method too :)- Proposed As Answer by ddpommes Wednesday, February 02, 2011 9:26 AM
-
Monday, November 30, 2009 3:07 PMhello everyone!
i have this probelm with programmically selecting a cell in WPF DataGrid too.
i'm using .NET 4.0 Beta 2.
i have MainWindow with DataGrid in it, for example such markup:
<DataGrid
Name="myDataGrid"
AutoGenerateColumns="False"
GridLinesVisibility="None"
IsReadOnly="True"
SelectionUnit="Cell"
SelectionMode="Single">
<DataGrid.Columns>
<!-- some columns -->
</DataGrid.Columns>
</DataGrid>
important thing is that in my DataGrid i need:
SelectionUnit="Cell"
SelectionMode="Single"
all solutions i've found (including in this thread) not works,
so i tried to do some stuff by myself, and this is what i got.
i've experimented with various proerties of DataGrid, it's event handlers, etc.
and finnaly, i looked at the property "myDataGrid.SelectedCells", in debug i find out,
that if i select only one cell, in "myDataGrid.SelectedCells" will be 1 item of type
"DataGridCellInfo", and it's "Column" proprty is not null!
so when you working with individual cells (like in my case),
all other properties like:
SelectedIndex, SelectedItem, CurrentCell, CurrentColumn, Items.*, ItemContainerGenerator.*, etc.
are useless, so you need to work with the prperty "SelectedCells" even if you are
working with a single cell.
so this is my solution wich i'm using now:
public partial class MainWindow {
private DataGridCellInfo[,] dataGridAllCells; //here will be stored all cells, displayed in DataGrid, as 2D matrix of cells
...
public MainWindow() {
InitializeComponent();
//here goes important stuff, this needs to be done each time, "myDataGrid.ItemsSource" is changed and all cells are regenerated
myDataGrid.ItemContainerGenerator.ItemsChanged += (sender, e) => {
//init matrix of cells
dataGridAllCells = new DataGridCellInfo[myDataGrid.Items.Count, myDataGrid.Columns.Count];
//changing "SelectionUnit" to "CellOrRowHeader", so we can select all cells of our DataGrid
myDataGrid.SelectionUnit = DataGridSelectionUnit.CellOrRowHeader;
//selecting all cells
myDataGrid.SelectAllCells();
//getting all selected cells (with proper "Column" property)
var allCellsArray = myDataGrid.SelectedCells.ToArray();//"ToArray()" is necessary, so we won't loose the cells during selection change
//initialize items of our cell matrix
for (int indexRow = 0, arrayCellsIndex = 0; indexRow < myDataGridt.Items.Count; indexRow++)
for (int indexColumn = 0; indexColumn < myDataGrid.Columns.Count; indexColumn++)
dataGridAllCells[indexRow, indexColumn] = allCellsArray[arrayCellsIndex++];
//setting back "SelectionUnit"
myDataGrid.SelectionUnit = DataGridSelectionUnit.Cell;
};
}
...
private void MoveToUpperCell_Click(object sender, RoutedEventArgs e) {
if (myDataGrid.SelectedCells.Count == 1) {
int indexRow = myDataGrid.Items.IndexOf(myDataGrid.SelectedCells[0].Item);//getting current selected row
int indexColumn = myDataGrid.Columns.IndexOf(myDataGrid.SelectedCells[0].Column);//getting current selected column
myDataGrid.SelectedCells.Clear();//clearing the selection
myDataGrid.SelectedCells.Add(dataGridAllCells[Math.Max(--indexRow, 0), indexColumn]);//and setting new selection we need
}
//selec some default cell if none is selected
else myDataGrid.SelectedCells.Add(dataGridAllCells[0, 1]);
//scroll to current selection
myDataGrid.ScrollIntoView(myDataGrid.SelectedCells[0].Item);
}
private void MoveToLowerCell_Click(object sender, RoutedEventArgs e) {
if (myDataGrid.SelectedCells.Count == 1) {
int indexRow = myDataGrid.Items.IndexOf(myDataGrid.SelectedCells[0].Item);
int indexColumn = myDataGrid.Columns.IndexOf(myDataGrid.SelectedCells[0].Column);
myDataGrid.SelectedCells.Clear();
myDataGrid.SelectedCells.Add(dataGridAllCells[Math.Min(++indexRow, myDataGrid.Items.Count - 1), indexColumn]);
}
else myDataGrid.SelectedCells.Add(dataGridAllCells[0, 1]);
myDataGrid.ScrollIntoView(myDataGrid.SelectedCells[0].Item);
}
...
}
so in this way you can programmicaly change selected cell as you need.
nya-nya! -
Tuesday, March 02, 2010 1:04 AM
When trying to implement the above in VB.Net 2008 with ToolKit with the following. SetCellFocus is intended to set the focus to the designate row and column for the designated datagrid and allow input.
Private Sub SetCellFocus(ByVal dgGrid As DataGrid, ByVal nRow As Integer, ByVal nCol As Integer) Dim dgCell As DataGridCell dgCell = GetCell(dgGrid, nRow, nCol) dgCell.Focus() dgGrid.BeginEdit() End Sub Private Function GetCell(ByRef dgGrid As DataGrid, ByVal nRow As Integer, ByVal nCol As Integer) As DataGridCell Dim dgRow As DataGridRow = GetRow(dgGrid, nRow) If dgRow IsNot Nothing Then Dim presenter As DataGridCellsPresenter presenter = GetVisualChild2(dgRow) Dim dgCell As DataGridCell dgCell = presenter.ItemContainerGenerator.ContainerFromIndex(nCol) If dgCell Is Nothing Then dgGrid.ScrollIntoView(dgRow, dgGrid.Columns(nCol)) dgCell = presenter.ItemContainerGenerator.ContainerFromIndex(nCol) End If GetCell = dgCell Else GetCell = Nothing End If End Function Private Function GetRow(ByRef dgGrid As DataGrid, ByVal nRow As Integer) As DataGridRow Dim row As DataGridRow = dgGrid.ItemContainerGenerator.ContainerFromIndex(nRow) If row Is Nothing Then dgGrid.ScrollIntoView(dgGrid.Items(nRow)) row = dgGrid.ItemContainerGenerator.ContainerFromIndex(nRow) End If GetRow = row End Function Function GetVisualChild2(ByRef dgRow As Visual) As DataGridCellsPresenter Dim v As Visual Dim nChildren As Integer Dim nChild As Integer Dim child As DataGridCellsPresenter child = Nothing nChildren = VisualTreeHelper.GetChildrenCount(dgRow) For nChild = 0 To nChildren - 1 v = VisualTreeHelper.GetChild(dgRow, nChild) child = CType(v, DataGridCellsPresenter) If child Is Nothing Then child = GetVisualChild2(v) Else Exit For End If Next GetVisualChild2 = child End FunctionEverything seems to be working except the GetVisualChild implementation. The GetChildCount of dgRow returns 0.
Appreciate any help that can be provided.
Bob -
Sunday, May 01, 2011 3:50 PM
Hello everybody
we have an important question about your solution.
Does myDataGrid.ScrollIntoView(dataObject) work in sync with UI Render Thread of WPF?
it means if we call myDataGrid.ScrollIntoView(dataObject) on the next line can we sure that ItemsContainerGenerator creates correspond DataGridRow for desired dataObject ?
it means ..
int index = 11;
myDataGrid.SelectedItem = myDataGrid.Items[index];
myDataGrid.ScrollIntoView(myDataGrid.Items[index]);
DataGridRow dgrow = (DataGridRow)myDataGrid.ItemContainerGenerator.ContainerFromItem(myDataGrid.Items[index]);//always dgrow!=null?
dgrow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));thank you for your answers
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/933b65b4-00ca-4fdd-8b15-615b8cc7c4ac/#3160bd4d-876a-4bd6-8b4b-b42d52626528 -
Tuesday, October 18, 2011 8:18 AMThanks Aran, your solution worked for me
-
Thursday, April 05, 2012 9:28 PM
I haven't had much luck the other ways, so i use this workaround
Thanks. This works for me too.
//first focus the grid grid.Focus(); //then create a new cell info, with the item we wish to edit and the column number of the cell we want in edit mode DataGridCellInfo cellInfo = new DataGridCellInfo(itemToSelect, grid.Columns[0]); //set the cell to be the active one grid.CurrentCell = cellInfo; //scroll the item into view grid.ScrollIntoView(itemToSelect); //begin the edit grid.BeginEdit();
this works for me. (it would make a nice little static method too :)
-
Friday, April 06, 2012 7:47 PM
I haven't had much luck the other ways, so i use this workaround
Worked perfectly for me!! Thanks.
//first focus the grid grid.Focus(); //then create a new cell info, with the item we wish to edit and the column number of the cell we want in edit mode DataGridCellInfo cellInfo = new DataGridCellInfo(itemToSelect, grid.Columns[0]); //set the cell to be the active one grid.CurrentCell = cellInfo; //scroll the item into view grid.ScrollIntoView(itemToSelect); //begin the edit grid.BeginEdit();
this works for me. (it would make a nice little static method too :)
-
Friday, April 20, 2012 1:46 PM
I have a new datagrid and when the user enters data in the first row the focus must be set to the beginning of second row first cell. At this time the second row does not exist in the grid. It's added after the first row is comitted. How can I achieve this using your code above. Also, in your code could you explain what is itemToSelect will be?
Thanks
Ragu
-
Friday, September 07, 2012 12:38 AM
DataGrid's CurrentCell (read/write) Property seemed the most obvious choice and surprise, surprise, actually worked for me!?! Woo-hoo!
NOTE: Unless you're dynamically generating the Columns, you should know, at compile time, the Name of the Column you want to Focus on. If so, you should give that Column a non-blank Name Property (aka "x.Name" XAML Attribute) and reference it by that name in the code. That way you avoid hard-coded Column Index Literals that are likely to break without letting you know at compile time, if you reorder / remove the Column.
FYI, I was doing this inside a Handler (inside the Code Behind of the View) of an Event Raised by an ICommand in the View Model bound to a Button in the View, so YMMV, if you're doing it using a different method.
<DataGrid x:Name="MyDatGrid" ... > ... <DataGridCheckboxColumn x:Name="TargDgCol" Header="Targ" ... > ... </DataGridCheckboxColumn> <!-- "TargDgCol" --> ... </DataGrid> <!-- "MyDatGrid" -->With MyDatGrd .CurrentCell = New DataGridCellInfo( .Items(TargRowIdxInt), TargDgCol ) End With ' -- MyDatGrd

