【问题标题】:Set the caret/cursor position to the end of the string value WPF textbox将插入符号/光标位置设置为字符串值 WPF 文本框的末尾
【发布时间】:2011-02-22 18:03:54
【问题描述】:

当我第一次打开窗口时,我尝试将插入符号/光标位置设置为 WPF 文本框中字符串值的 end。当我的窗口打开时,我使用 FocusManager 将焦点设置在我的文本框上。

似乎没有任何效果。有什么想法吗?

注意,我使用的是 MVVM 模式,并且我只包含了我的代码中的一部分 XAML。

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

【问题讨论】:

    标签: wpf textbox caret cursor-position


    【解决方案1】:

    您可以使用TextBoxCaretIndex 属性设置插入符号位置。请记住,这不是DependencyProperty。尽管如此,您仍然可以像这样在 XAML 中设置它:

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

    请记住设置CaretIndex after Text 属性,否则它将不起作用。因此,如果您像示例中那样绑定到Text,它可能不起作用。在这种情况下,只需像这样使用代码隐藏。

    NumberOfDigits.CaretIndex = NumberOfDigits.Text.Length;
    

    【讨论】:

      【解决方案2】:

      您还可以创建一个行为,虽然它仍然是代码隐藏的,但具有可重用的优势。

      一个简单的行为类示例,使用文本框的焦点事件:

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

      然后,在您的 XAML 中,附加如下行为:

          <TextBox x:Name="MyTextBox" Text="{Binding Value}">
              <i:Interaction.Behaviors>
                  <behaviors:PutCursorAtEndTextBoxBehavior/>
              </i:Interaction.Behaviors>
          </TextBox>
      

      【讨论】:

        【解决方案3】:

        这对我有用。我也在使用 MVVM 模式。但是,我使用 MMVM 的目的是使单元测试成为可能,并更容易更新我的 UI(松散耦合)。我没有看到自己对光标的位置进行单元测试,所以我不介意为这个简单的任务求助于背后的代码。

            public ExpeditingLogView()
            {
                InitializeComponent();
        
                this.Loaded += (sender, args) =>
                {                                
                    Description.CaretIndex = Description.Text.Length;
                    Description.ScrollToEnd();
                    Description.Focus();
                };
            }
        

        【讨论】:

          【解决方案4】:

          如果是多行TextBox 设置光标是不够的。 试试这个:

          NumberOfDigits.ScrollToEnd();
          

          【讨论】:

          • 仅代码答案不是好的答案,添加几行来解释问题所在以及您的代码修复它的原因
          【解决方案5】:

          在 WPF 中,如果行足够长,滚动到行尾也很重要。所以我使用以下几行:

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

          但请阅读此警告(对我来说这很好 - 可能已经修复): TextBox ScrollToHorizontalOffset will not scroll after text is long enough

          【讨论】:

            【解决方案6】:

            如果textbox 用于模板绑定或任何类型的惰性绑定或惰性值分配,@Louis 解决方案将不起作用

            因此,如果 textbox 在 Datagrid 单元格中用作模板,该解决方案将需要进行微小的修改才能工作

            那就是订阅文本更改事件

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

            【讨论】:

              【解决方案7】:

              这里没有一个答案对我有用。我正在为 TextBox 使用绑定,并且需要在窗口弹出后立即移动插入符号。这是为我做的:

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

              类似于 Ceranski 的回答。我们添加到ContentRendered,而不是添加到Loaded 事件。

              【讨论】:

              • 它对我有用,但 MyTextBox.ScrollToEnd() 不是必需的。
              【解决方案8】:

              由于某些原因,我不得不使用:

              Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => 
              {
                  textBox.CaretIndex = textBox.Text.Length;
                  textBox.ScrollToEnd();
              }));
              

              【讨论】:

                【解决方案9】:
                【解决方案10】:

                我想创建一个用户控件/视图,其中包含绑定到 ViewModel 的预填充文本框,当控件打开时,焦点会自动设置在文本框和末尾的插入符号位置。这是我让它工作的唯一方法:

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

                到目前为止似乎工作得很好......

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-01-08
                  • 1970-01-01
                  相关资源
                  最近更新 更多