Set the caret/cursor position to the end of the string value WPF textbox
Asked Answered
F

11

87

I am try to set the caret/cursor position to the end of the string value in my WPF textbox when I open my window for the first time. I use the FocusManager to set the focus on my textbox when my window opens.

Nothing seems to work. Any ideas?

Note, I am using the MVVM pattern, and I included only a portion of the XAML from my code.

<Window 
    FocusManager.FocusedElement="{Binding ElementName=NumberOfDigits}"
    Height="400" Width="800">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBox Grid.Column="0" Grid.Row="0" 
                 x:Name="NumberOfDigits"
                 IsReadOnly="{Binding Path=IsRunning, Mode=TwoWay}"
                 VerticalContentAlignment="Center"
                 Text="{Binding Path=Digits, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Grid.Column="0" Grid.Row="1" 
                 Margin="10,0,10,0"
                 IsDefault="True"
                 Content="Start" 
                 Command="{Binding StartCommand}"/>
    </Grid>
 </Window>
Foreplay answered 22/5, 2010 at 16:49 Comment(0)
L
125

You can set the caret position using CaretIndex property of a TextBox. Please bear in mind that this is not a DependencyProperty. Nevertheless, you may still set it in XAML like this:

<TextBox Text="123" CaretIndex="{x:Static System:Int32.MaxValue}" />

Please remember to set CaretIndex after Text property or else it will not work. Thus it probably won't work if you bind to Text like in your example. In that case, simply use code-behind like this.

NumberOfDigits.CaretIndex = NumberOfDigits.Text.Length;
Labourite answered 23/5, 2010 at 18:52 Comment(0)
T
26

You may also create a Behavior, which, while still being code-behind, has the advantage of being reusable.

Example of a simple behavior class, using the focus event of the textbox:

class PutCursorAtEndTextBoxBehavior: Behavior<UIElement>
{
   private TextBox _textBox;

   protected override void OnAttached()
   {
        base.OnAttached();

        _textBox = AssociatedObject as TextBox;

        if (_textBox == null)
        {
            return;
        }
        _textBox.GotFocus += TextBoxGotFocus;
   }

    protected override void OnDetaching()
    {
        if (_textBox == null)
        {
            return;
        }
        _textBox.GotFocus -= TextBoxGotFocus;

        base.OnDetaching();
    }

    private void TextBoxGotFocus(object sender, RoutedEventArgs routedEventArgs)
    {
        _textBox.CaretIndex = _textBox.Text.Length;
    }
}    

Then, in your XAML, you attach the behavior like so:

    <TextBox x:Name="MyTextBox" Text="{Binding Value}">
        <i:Interaction.Behaviors>
            <behaviors:PutCursorAtEndTextBoxBehavior/>
        </i:Interaction.Behaviors>
    </TextBox>
Takeo answered 21/8, 2013 at 20:4 Comment(0)
S
5

This worked for me. I am also using the MVVM pattern. However, my purpose for using a MMVM is to make unit testing possible and to make it easier to update my UI (loosely coupled). I don't see myself unit testing the position of the cursor so I don't mind resorting to the code behind for this simple task.

    public ExpeditingLogView()
    {
        InitializeComponent();

        this.Loaded += (sender, args) =>
        {                                
            Description.CaretIndex = Description.Text.Length;
            Description.ScrollToEnd();
            Description.Focus();
        };
    }
Sherwoodsherwynd answered 9/6, 2017 at 14:4 Comment(0)
C
4

In WPF if line is long enough it is important also to scroll to the end of the line. So i'm using the following lines:

text_Box.Text = text;
text_Box.CaretIndex = text.Length;
text_Box.ScrollToHorizontalOffset(double.MaxValue);
// or you can use this - for me works also
// text_Box.ScrollToHorizontalOffset(text_Box.GetRectFromCharacterIndex(openFileDialog.FileName.Length).Right);

but read this caution (for me it's fine - probably already fixed): TextBox ScrollToHorizontalOffset will not scroll after text is long enough

Cuspid answered 8/11, 2019 at 19:58 Comment(0)
C
4

None of the answers here worked for me. I'm using binding for the TextBox and needed to move the caret right after the window poped up. This did it for me:

public MyWindow()
{
    InitializeComponent();

    ContentRendered += (sender, args) =>
    {
        MyTextBox.CaretIndex = MyTextBox.Text.Length;
        MyTextBox.ScrollToEnd(); // not necessary for single line texts
        MyTextBox.Focus();
    };
}

Similar to Ceranski answer. Instead of adding to the Loaded event we add to ContentRendered.

Carob answered 18/12, 2019 at 8:45 Comment(1)
It worked for me but MyTextBox.ScrollToEnd() was not necessary.Aniela
H
4

@Louis solution will not work if textbox used in template binding or any type of lazy bindings or lazy value assignments

So if the textbox used for example in Datagrid cell as a template that solution will need for tiny modification to work

and that is subscribing to text changed event

 class PutCursorAtEndTextBoxBehavior : Behavior<UIElement>
    {
        private TextBox _textBox;

        protected override void OnAttached()
        {
            base.OnAttached();

            _textBox = AssociatedObject as TextBox;

            if (_textBox == null)
            {
                return;
            }
            _textBox.GotFocus += TextBoxGotFocus;
            // to make it work with binding
            _textBox.TextChanged += TextBoxGotFocus;
        }

        protected override void OnDetaching()
        {
            if (_textBox == null)
            {
                return;
            }
            _textBox.GotFocus -= TextBoxGotFocus;
            _textBox.TextChanged -= TextBoxGotFocus;

            base.OnDetaching();
        }

        private void TextBoxGotFocus(object sender, RoutedEventArgs routedEventArgs)
        {
            _textBox.CaretIndex = _textBox.Text.Length;
        }
    }
Haler answered 12/5, 2020 at 5:11 Comment(0)
H
3

In case of multiline TextBox setting cursor is not enough. Try this:

NumberOfDigits.ScrollToEnd();
Hardison answered 26/9, 2016 at 11:41 Comment(1)
Code only answer are not good answers, add a few lines to explain what the problem was and why your code fixed itStrung
I
0

For some reasons I had to use :

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => 
{
    textBox.CaretIndex = textBox.Text.Length;
    textBox.ScrollToEnd();
}));
Inerrant answered 18/2, 2021 at 12:46 Comment(0)
B
0

I wanted to create a UserControl / View with a pre-populated textbox bound to a ViewModel, and when the control opens up, focus is automatically set on the textbox and the caret position at the end. This was the only way I got it to work:

public TextBoxDialogView()
{
    InitializeComponent();

    TextBox.GotKeyboardFocus += (sender, args) =>
    {
        TextBox.CaretIndex = TextBox.Text.Length;
    };
    _ = TextBox.Focus();
}

Seems to work nicely so far...

Baldhead answered 8/7, 2021 at 13:22 Comment(0)
O
0

WPF TextBox.Focus(); TextBox.CaretIndex = TextBox.Text.Length + 1;

Owades answered 11/7, 2023 at 13:35 Comment(2)
Isn't this exactly the same as the accepted answer? If not, please explain.Fiberglass
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Chit

© 2022 - 2024 — McMap. All rights reserved.