Setzen Sie die Caret- / Cursorposition auf das Ende des WPF-Textfelds für den Zeichenfolgenwert

75

Ich versuche, die Caret- / Cursorposition auf das Ende des Zeichenfolgenwerts in meinem WPF-Textfeld zu setzen, wenn ich mein Fenster zum ersten Mal öffne. Ich benutze den FocusManager, um den Fokus auf mein Textfeld zu setzen, wenn mein Fenster geöffnet wird.

Nichts scheint zu funktionieren. Irgendwelche Ideen?

Beachten Sie, dass ich das MVVM-Muster verwende und nur einen Teil der XAML aus meinem Code aufgenommen habe.

<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>
Zamboni
quelle

Antworten:

104

Sie können die Caret-Position mit der CaretIndexEigenschaft von a festlegen TextBox. Bitte beachten Sie, dass dies kein ist DependencyProperty. Trotzdem können Sie es in XAML wie folgt einstellen:

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

Bitte denken Sie daran, CaretIndex nach Text Eigenschaft zu setzen, sonst wird es nicht funktionieren. Daher wird es wahrscheinlich nicht funktionieren, wenn Sie sich an Textdas Beispiel binden . Verwenden Sie in diesem Fall einfach Code-Behind wie folgt.

NumberOfDigits.CaretIndex = NumberOfDigits.Text.Length;
wpfwannabe
quelle
2
Ja, ich habe versucht, mich an CaretIndex zu binden, und das ist fehlgeschlagen. Das Hinzufügen Ihres Codes zum CodeBehind im Fenster geladenen Ereignis hat hervorragend funktioniert. Vielen Dank.
Zamboni
26

Sie können auch ein Verhalten erstellen, das zwar immer noch Code-Behind ist, aber den Vorteil hat, dass es wiederverwendbar ist.

Beispiel einer einfachen Verhaltensklasse unter Verwendung des Fokusereignisses des Textfelds:

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;
    }
}    

Dann hängen Sie in Ihrer XAML das Verhalten wie folgt an:

    <TextBox x:Name="MyTextBox" Text="{Binding Value}">
        <i:Interaction.Behaviors>
            <behaviors:PutCursorAtEndTextBoxBehavior/>
        </i:Interaction.Behaviors>
    </TextBox>
Louis
quelle
1
Dies ist die beste Lösung. Das manuelle Setzen des Cursors ist ein Schmerz im Arsch.
Darkhydro
4

Das hat bei mir funktioniert. Ich benutze auch das MVVM-Muster. Mein Zweck für die Verwendung einer MMVM ist es jedoch, Unit-Tests zu ermöglichen und die Aktualisierung meiner Benutzeroberfläche (lose gekoppelt) zu vereinfachen. Ich sehe mich nicht als Einheit, der die Position des Cursors testet, daher macht es mir nichts aus, für diese einfache Aufgabe auf den Code dahinter zurückzugreifen.

    public ExpeditingLogView()
    {
        InitializeComponent();

        this.Loaded += (sender, args) =>
        {                                
            Description.CaretIndex = Description.Text.Length;
            Description.ScrollToEnd();
            Description.Focus();
        };
    }
Michael Ceranski
quelle
3

Bei mehrzeiliger TextBoxEinstellung reicht der Cursor nicht aus. Versuche dies:

NumberOfDigits.ScrollToEnd();
andreikashin
quelle
Nur Code-Antworten sind keine guten Antworten. Fügen Sie ein paar Zeilen hinzu, um zu erklären, was das Problem war und warum Ihr Code es behoben hat
MikeT
2

Wenn in WPF die Zeile lang genug ist, ist es wichtig, auch zum Zeilenende zu scrollen. Also benutze ich die folgenden Zeilen:

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);

Aber lesen Sie diese Warnung (für mich ist es in Ordnung - wahrscheinlich bereits behoben): TextBox ScrollToHorizontalOffset scrollt nicht, nachdem der Text lang genug ist

Andrey der Autobot
quelle
1

Die @ Louis-Lösung funktioniert nicht, wenn textboxsie für die Vorlagenbindung oder für andere Arten von verzögerten Bindungen oder verzögerten Wertzuweisungen verwendet wird

Also wenn die textbox Lösung beispielsweise in einer Datagrid-Zelle als Vorlage verwendet wird, muss diese Lösung geringfügig geändert werden

und das ist das Abonnieren eines textveränderten Ereignisses

 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;
        }
    }
Al Banna Techno logie
quelle
0

Keine der Antworten hier hat bei mir funktioniert. Ich verwende die Bindung für die TextBox und musste das Caret direkt nach dem Öffnen des Fensters verschieben. Das hat es für mich getan:

public MyWindow()
{
    InitializeComponent();

    ContentRendered += (sender, args) =>
    {
        MyTextBox.CaretIndex = MyTextBox.Text.Length;
        MyTextBox.ScrollToEnd();
        MyTextBox.Focus();
    };
}

Ähnlich wie bei Ceranski. Anstatt zu Loaded hinzuzufügen, fügen wir ContentRendered hinzu.

Flourick
quelle