WPF DataGrid: Tabbing from cell to cell does not set focus on control
August 21, 2009
When DataGrid was introduced into WPF, I was happy. I really lack this control. As many other developers I found one drawback of new control. When you use DataGridTemplateColumn, it doesn’t set focus automatically on control inside DataGridTemplateColumn.CellEditingTemplate. This requires from you to click 3 times to edit the cell or press tab twice. It is very annoying. Discussion of this bug and possible solutions was made at code plex http://www.codeplex.com/Thread/View.aspx?ProjectName=wpf&ThreadId=35540 . I found my own solution. When you start to edit cell, wpf creates controls for data edit, like textboxes. So we need to transfer focus to them immediately. I created attacher class:
public class FocusAttacher
{
public static readonly DependencyProperty FocusProperty = DependencyProperty.RegisterAttached("Focus", typeof(bool), typeof(FocusAttacher), new PropertyMetadata(false, FocusChanged));
public static bool GetFocus(DependencyObject d)
{
return (bool)d.GetValue(FocusProperty);
}
public static void SetFocus(DependencyObject d, bool value)
{
d.SetValue(FocusProperty, value);
}
private static void FocusChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
((UIElement)sender).Focus();
}
}
}
Public Class FocusAttacher Public Shared ReadOnly FocusProperty As DependencyProperty = DependencyProperty.RegisterAttached(“Focus”, GetType(Boolean), GetType(FocusAttacher), New PropertyMetadata(False, New PropertyChangedCallback(AddressOf FocusChanged))) Public Shared Function GetFocus(ByVal d As DependencyObject) As Boolean Return CBool(d.GetValue(FocusProperty)) End Function Public Shared Sub SetFocus(ByVal d As DependencyObject, ByVal value As Boolean) d.SetValue(FocusProperty, value) End Sub Private Shared Sub FocusChanged(ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs) If CBool(e.NewValue) Then DirectCast(sender, UIElement).Focus() End If End Sub End Class
As you can see, this class can be attached to any UIElement and calls focus immediately.
You can use it like this:
<tk:DataGrid CanUserAddRows="True" ItemsSource="{Binding}" AutoGenerateColumns="False">
<tk:DataGrid.Columns>
<tk:DataGridTemplateColumn Header="Name">
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Padding="3" Text="{Binding Name}" />
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
<tk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Name, Mode=OneWay}" lc:FocusAttacher.Focus="True" />
</DataTemplate>
</tk:DataGridTemplateColumn.CellEditingTemplate>
</tk:DataGridTemplateColumn>
<tk:DataGridTemplateColumn Header="Phone">
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Phone}" Padding="3"/>
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
<tk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Phone, Mode=OneWay}" lc:FocusAttacher.Focus="True" />
</DataTemplate>
</tk:DataGridTemplateColumn.CellEditingTemplate>
</tk:DataGridTemplateColumn>
<tk:DataGridTemplateColumn Header="Address">
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Address}" Padding="3"/>
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
<tk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Address, Mode=OneWay}" lc:FocusAttacher.Focus="True" />
</DataTemplate>
</tk:DataGridTemplateColumn.CellEditingTemplate>
</tk:DataGridTemplateColumn>
</tk:DataGrid.Columns>
</tk:DataGrid>
This completely solves the problem, when you start to edit cell, focus immediately goes to required control.
Sample projects which show such datagrid and attacher class in action is available .
Thanks, that certainly solved the issue for me. There is however a little bit missing in the VB version of the code. The FocusProperty declaration should be:
Public Shared ReadOnly FocusProperty As DependencyProperty = DependencyProperty.RegisterAttached(“Focus”, GetType(Boolean), GetType(FocusAttacher), New PropertyMetadata(False, New PropertyChangedCallback(AddressOf FocusChanged)))
How do you do ti, blog.yalovoi.net?
http://eftgentleness.blogspot.com/
blog.yalovoi.net, how do you do it?
http://chattinessknotty.blogspot.com/2010/03/cyclical-sector.html
Thanks!
Thank you, that’s really cool.
Do you happen to know how to automatically switch into editing mode when the user types in the cell? We get this for free with DataGridTextColumn but not for DataGridTemplateColumn.
Help me! The link of Sample projects don’t work…
I try to meke a simple progect but my solution don’t work.. plese explane me where i have to add a class for see the property in the xaml.