I am facing a strange problem with the WPF DataGrid. If you click the first cell, enter a value and then tab to the next cell, the first cell does not exit editing mode. I have reproduced the problem using a simplified version of the templates below:
<DataGrid Name="grid" HorizontalAlignment="Stretch" ItemsSource="{Binding Persons}" Margin="0,10,0,0" VerticalAlignment="Stretch" AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="FirstName">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding FirstName}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="LastName">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding LastName}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding LastName}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Age">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Age}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Age}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The dummy class definition is:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
The code behind is:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Persons = new ObservableCollection<Person>();
this.grid.CurrentCellChanged += grid_CurrentCellChanged;
this.grid.PreparingCellForEdit += grid_PreparingCellForEdit;
}
void grid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
if (e.EditingElement != null)
SetFocusToTextBox(e.EditingElement);
}
void grid_CurrentCellChanged(object sender, EventArgs e)
{
((DataGrid)sender).BeginEdit();
}
public ObservableCollection<Person> Persons { get; set; }
void SetFocusToTextBox(object obj)
{
// Get all children and examine if the child is a TextBox
object obChild;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj as DependencyObject); i++)
{
obChild = VisualTreeHelper.GetChild(obj as DependencyObject, i);
if (obChild is TextBox)
{
((TextBox)obChild).Focus();
break;
}
else
SetFocusToTextBox(obChild);
}
}
Does anyone see what's wrong here? Are you able to reproduce the issue? Any help will be appreciated.
Thanks, Bhanu
The DataGrid XAML definition is 100% correct. The problem must lie in code behind. My best guess is CurrentCellChanged. It could be raised two times. First when you leave a cell and secondly when a new cell is selected. If that is the case, you are putting the cell that lost focus back into editing mode, because you aren't checking the condition of the event.
You should be able to verify this with a simple debugging - put a break point at
((DataGrid)sender).BeginEdit()
and count the number of times it gets called.
I personally use the following code for BeginEdit and it works flawlesly:
private void dataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
if (e.AddedCells.Count > 0 && !this.dataGrid.IsReadOnly)
{
this.dataGrid.BeginEdit();
}
}