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 .

About these ads

9 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. Clark said

    How do you do ti, blog.yalovoi.net?

    http://eftgentleness.blogspot.com/

  3. Andrew said

    Thanks!

  4. Jonathan Allen said

    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.

  5. Alessandro said

    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.

  6. Mitesh Patel said

    WPF DataGrid: Tabbing from cell to cell does not set focus on control

    I tried this but did not work.
    But then I found one simple and effective technique which worked like champ!!!
    This need only 2 steps.

    1. Add Style in your resource file:

    2. Add this style in your data Grid:

    That is it. This has solved all the problem. No more work, no more class needs to be added.

    Happy Codding!!!!!!!!!!!!!!!!!

  7. Mitesh Patel said

    I tried many thigs which I found in different blog, but those did not work.
    But then I found one simple and effective technique which worked like champ!!!

    This need only 2 steps.

    1. Add Style in your resource file:

    2. Add this style in your data Grid:

    That is it. This has solved all the problem. No more work, no more class needs to be added.

    Happy Codding!!!!!!!!!!!!!!!!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: