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 .

2 Responses to “WPF DataGrid: Tabbing from cell to cell does not set focus on control”

  1. Andreas said

    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)))

  2. funny

    downloads games download funny video.

Leave a Reply