简体   繁体   中英

How do I tab between text boxes on a form in C#?

I'm trying to get the functionality to tab to the next text box once the user has input their data for the previous text box. For example, once they filled in a company name I'd like to be able to hit Tab and set the focus on the next text box "Job Name". Is this done in the code or the form properties?

Here is some of my code. I'm unsure how to nest a KeyEventsArgs within these, which is how I've seen others set the focus to the next text boxes using the KeyPress function.

private void textBox1_TextChanged(object sender, EventArgs e)
{
    CompanyName = textBox1.Text;
    textBox1.AcceptsTab = true;
}

private void textBox2_TextChanged(object sender, EventArgs e)
{
    JobName = textBox2.Text;
    textBox2.AcceptsTab = true;
}

From the question you've asked and the code sample provided, there seems to be somewhat of a disconnect between your approach and the desired functionality.

As you would like the user to be able to use the Tab key in order to shift keyboard focus between elements in the window, you need only provide a TabIndex attribute on each of your TextBox controls. There is no need to use the TextChanged events to achieve this and it can be done completely in XAML for simplicity's sake.

From how I interpret your question, your next follow-on will likely be:

How do I initially give focus to a control when the application starts?

To address this, there are a couple of alternatives available, simplest of which comes in the form of the FocusManager, which again I've illustrated usage of in XAML.

For convenience, here is a XAML-only implementation with TabIndex and FocusManager implemented:

<Window x:Class="tab_navigation.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:tab_navigation"
    mc:Ignorable="d"
    Title="MainWindow" ResizeMode="NoResize" SizeToContent="WidthAndHeight" FocusManager.FocusedElement="{Binding ElementName=TbxCompanyName}">
<Grid Margin="10">
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Vertical" Margin="0,0,0,10">
            <Label Content="Company Name:" Target="{Binding ElementName=TbxCompanyName}" />
            <TextBox Name="TbxCompanyName" TabIndex="0" Width="160" HorizontalAlignment="Left"/>
        </StackPanel>
        <StackPanel Orientation="Vertical">
            <Label Content="Job Description:" Target="{Binding ElementName=TbxJobDescription}"/>
            <TextBox Name="TbxJobDescription" TabIndex="1" Width="160" HorizontalAlignment="Left"/>
        </StackPanel>
    </StackPanel>

</Grid>

Give me a shout if you need any further help, although I would strongly recommend checking out some of the MSDN resources first, particularly those concerning Focus

UPDATE : In response to comment regarding implementing the solution, WPF has a different design and best practices from that of WinForms. I would strongly make the case that you cease using Forms and instead use a Window or UserControl derived class in place of a Form in your WPF project unless there is a very, very good reason for doing so. If you continue to use a Form inside of your WPF project, you will indeed need to implement your own keyboard navigation logic inside that form, and bridge various other gaps you'll inevitably run into when trying to get a Form behave in a commonly acceptable way. I'll instead show you how you can achieve your request using an objectively better and more suitable approach in WPF-only, using Window or UserControl elements. There is also a complete solution zip downloadable here .

WPF is by design a lot more modular than WinForms and splits the areas of concerns nicely by default, although most developers implement a design pattern ontop of this; MVVM is the current darling of WPF, and does add quite a lot of value to a project, although it is outside the scope of your question, so I shall instead address the question itself on the grounds of how to achieve the request in its most basic forms. Do please be aware though that this is not the entirely ideal solution and I would strongly recommend you learn and implement the MVVM pattern for WPF if you are not already familiar with it.

With that disclaimer out of the way, instead of using a Form in WPF , its more useful for us to make a class which derives from Window . An even more common scenario in WPF would be that you would want to have a single window whose content changes between different views, rather than say creating multiple windows, although again that is outside the scope of the question and would rely upon reading into Binding and MVVM. I'm going to be showing you a quick and easy way to get the functionality you've asked for, I'm just trying to iterate here that this is not the norm almost all of the time.

To make a working solution, do the following to your project:

  1. Right click your project in the solution explorer (presuming you are using Visual Studio)
  2. 'Add' a 'New Item...'.
  3. Choose the 'Window (WPF)' template and name it. I'm going to call it CustomerInformationEntry from here out .
  4. Open the CustomerInformationEntry.xaml file that has been created for us, remove the <Grid></Grid> tags and copy/paste this excerpt from the XAML I've already provided from above in their place:

<Grid Margin="10"> <StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical" Margin="0,0,0,10"> <Label Content="Company Name:" Target="{Binding ElementName=TbxCompanyName}" /> <TextBox Name="TbxCompanyName" TabIndex="0" Width="160" HorizontalAlignment="Left"/> </StackPanel> <StackPanel Orientation="Vertical"> <Label Content="Job Description:" Target="{Binding ElementName=TbxJobDescription}"/> <TextBox Name="TbxJobDescription" TabIndex="1" Width="160" HorizontalAlignment="Left"/> </StackPanel> </StackPanel> </Grid>

  1. Add FocusManager.FocusedElement="{Binding ElementName=TbxCompanyName} to the Window element in CustomerInformationEntry.xaml .
  2. This is our view or visual representation finished with now, and all that remains is to instanciate a new CustomerInformationEntry from our other Window or UserControl, and to then display it. In this case I'm going to be putting a button onto the MainWindow.xaml , and providing it a click event which will create the instance of our new Window:
    • In MainWindow.xaml add <Button Name="BtnOpenCustomerInformationEntry" Content="Enter Customer Information" Click="OpenCustomerInformationEntry"/> . In my case I'll be adding the button inside my object, although you can put it wherever you like if you've already created your initial window.
    • In MainWindow.xaml.cs we'll add a new private method which will be used by the Click event of your new button. Adding the following code:

private void OpenCustomerInformationEntry(object sender, RoutedEventArgs e) { CustomerInformationEntry myWindow = new CustomerInformationEntry(); myWindow.Show(); }

That's it, you now have a button in your MainWindow.xaml which when clicked uses the OpenCustomerInformationEntry method defined in MainWindow.xaml.cs, which in turn makes an instance of your CustomerInformationEntry window and displays it.

If you would still rather stick with the Forms approach, you can do that by using WindowsFormsHost , usage of which is discussed here .

Best Regards, JC

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM