Control Class & Tab Order in WPF

Introduction

This article explains the Control class and Tab order. The Control class is a base class for Windows Presentation Foundation (WPF) controls. It inherits from the FrameworkElement type. Unlike FrameworkElement and the other WPF base classes, Control is not a super class for all of the WPF layout controls. It is the base class only for controls that have a template. These controls that can be heavily customised by replacing the basic template with new visuals.

Background

We will be looking at the process of modifying a control's template. We'll be seeing some of the other properties and events supplied by Control. We will also consider a window's tab order.

Solution

It's important for users to be able to navigate the controls logically with key presses. Microsoft Windows uses the concept of a tab order for keyboard navigation. Pressing the tab key moves the focus between controls. The tab order determines in which order items are visited when pressing tab. The order is reversed if the user holds the Shift key whilst tapping tab.

Procedure

The default tab order for a window is determined by the position of each control within the logical tree. When pressing only the tab key, the first control visited will be the one that is closest to the top of the tree. Further taps of the key will move the focus through the tree. In many cases the tab order matches the order in which controls are defined in the XAML.

Step 1

 Create a new WPF application project in Visual Studio. Name the project "ControlTabOrderDemo". Once the project is initialised, replace the XAML in the main window with the code below:

<Window x:Class="ControlTabOrderDemo.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Control Demo"

        Height="150"

        Width="250">

    <DockPanel Background="Orange">

        <Button DockPanel.Dock="Bottom"

                HorizontalAlignment="Right"

                VerticalAlignment="Bottom"

                Margin="2"

                Width="75"

                IsTabStop="False">Save</Button>

 

        <Grid Background="PeachPuff">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition/>

            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>

                <RowDefinition Height="25"/>

                <RowDefinition Height="25"/>

                <RowDefinition Height="25"/>

                <RowDefinition/>

            </Grid.RowDefinitions>

 

            <Label>First Name</Label>

            <TextBox Grid.Column="1" Height="22" TabIndex="0"/>

 

            <Label Grid.Row="1">Initials</Label>

            <TextBox Name="Test" Grid.Column="1" Grid.Row="1" Height="22" TabIndex="1"/>

 

            <Label Grid.Row="2">Last Name</Label>

            <TextBox Grid.Column="1" Grid.Row="2" Height="22" TabIndex="2"/>

        </Grid>

    </DockPanel>

</Window>

Here we have three labels and three TextBoxes. Also we have defined the background color of dock panel. We have defined the horizontal and vertical alignment for the dockpanel.

Step 2

The logical tree created by the preceding XAML places the DockPanel, that contains a button, before the Grid holding three text boxes.
Although the button is high in the XAML, it will appear at the bottom of the window due to the selected Dock option.

 co

 Step 3

Since the DockPanel and Grid cannot receive the focus, the items that you can tab among are the Save button, followed by the First Name, Initials and Last Name text boxes. This is the default tab order, that might come as a surprise to users who expect the first press of the tab key to set the focus to the First Name text box.This is a reasonable assumption, since the text box appears at the top of the window.

Step 4

Use the following interaction logic for the main window.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

 

namespace ControlTabOrderDemo

{

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

        }

    }

}