Keyboard helper class for wp7 vs tab index

I’ve recently blogged on tumblr about a way to plug the missing tab-to-next-control functionaly in wp7 when using the software keyboard (SIP). I’ve reafactored the code to make it a little easier to use, plus added a little bug fix concerning isEnabled=false controls.

<!--ContentPanel - place additional content here-->

<Grid x:Name="ContentGrid" Grid.Row="1">

  <StackPanel Orientation="Vertical">

    <CheckBox IsTabStop="True" TabIndex="4" Content="Some check"></CheckBox>

    <TextBox TabIndex="1" Text="start here" KeyUp="TextBox_KeyUp"></TextBox>

    <TextBox IsTabStop="True" Text="Won't tab here cause not set tabindex"></TextBox>

    <TextBox IsEnabled="False" TabIndex="2" Text="not here cause disabled" KeyUp="TextBox_KeyUp"></TextBox>

    <TextBox TabIndex="3" Text="next stop here" KeyUp="TextBox_KeyUp"></TextBox>

  </StackPanel>

</Grid>


A little bit of code-behind is needed;

public partial class MainPage : PhoneApplicationPage

{

    private KeyboardHelper keyboardHelper;

 

    public MainPage()

    {

        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MainPage_Loaded);

        this.IsTabStop = true;

    }

 

    void MainPage_Loaded(object sender, RoutedEventArgs e)

    {

        this.keyboardHelper = new KeyboardHelper(this, LayoutRoot);

    }

 

    private void TextBox_KeyUp(object sender, KeyEventArgs e)

    {

        if (e.Key == Key.Enter)

        {

            keyboardHelper.HandleReturnKey(sender);

        }

    }

}

…and the supporting helper class;

// Wp7Keyboard helper by @pauliom

using System;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Media;

using System.Collections.Generic;

using Microsoft.Phone.Controls;

 

namespace Wp7Keyboard

{

    /// <summary>

    /// Helper to provide missing tab-to-next-control functionality

    /// </summary>

    public class KeyboardHelper

    {

        private List<Control> tabbedControls;

        private Control lastTabbedControl = null;

        private Panel layoutRoot;

        private PhoneApplicationPage page;

 

        /// <summary>

        /// Constructor to support a phone page

        /// </summary>

        /// <param name="page"></param>

        /// <param name="layoutRoot"></param>

        public KeyboardHelper(PhoneApplicationPage page, Panel layoutRoot)

        {

            this.layoutRoot = layoutRoot;

            this.page = page;

            RefeshTabbedControls(layoutRoot);

        }

 

        /// <summary>

        /// Refresh the tabbed controls collection, helpful if you dynamically alter the controls

        /// </summary>

        /// <param name="layoutRoot"></param>

        public void RefeshTabbedControls(Panel layoutRoot)

        {

            this.tabbedControls = GetChildsRecursive(layoutRoot).OfType<Control>().Where(c => c.IsTabStop && c.TabIndex != int.MaxValue).OrderBy(c => c.TabIndex).ToList();

            if (this.tabbedControls != null && this.tabbedControls.Count > 0)

            {

                this.lastTabbedControl = this.tabbedControls[this.tabbedControls.Count - 1];

            }

        }

 

        // code from 'tucod'

        IEnumerable<DependencyObject> GetChildsRecursive(DependencyObject root)

        {

            List<DependencyObject> elts = new List<DependencyObject>();

            elts.Add(root);

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)

                elts.AddRange(GetChildsRecursive(VisualTreeHelper.GetChild(root, i)));

 

            return elts;

        }

 

        /// <summary>

        /// Process a return key from the client controls key-up event

        /// </summary>

        /// <param name="sender"></param>

        internal void HandleReturnKey(object sender)

        {

            Control eventSender = sender as Control;

            if (eventSender != null)

            {

                Control thisControlInTabbedList = tabbedControls.FirstOrDefault(c => c == eventSender);

                if (thisControlInTabbedList != null)

                {

                    // what's the next control?                                                                       

                    SetFocusOnNextControl(thisControlInTabbedList);

                }

            }

        }

 

        private void SetFocusOnNextControl(Control thisControlInTabbedList)

        {

            if (lastTabbedControl == thisControlInTabbedList)

            {

                // we've come the end so remove the keyboard

                this.page.Focus();

            }

            else

            {

                Control nextControl = tabbedControls.FirstOrDefault(c => c.TabIndex > thisControlInTabbedList.TabIndex);

                bool wasFocusSet = false;

                if (nextControl != null)

                {

                    wasFocusSet = nextControl.Focus();

                }

 

                if (!wasFocusSet)

                {

                    SetFocusOnNextControl(nextControl);

                }

 

            }

        }

    }

}

Hope you find it useful, again maybe it won’t be needed after RTM, finders crossed.
BTW I’m trying out new blog engines hence the scatter of links.

One thought on “Keyboard helper class for wp7 vs tab index

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 )

Facebook photo

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

Connecting to %s