Переключите содержимое двух текстовых полей WPF и ScrollToEnd ()

1

Я пытаюсь переключить текст двух текстовых полей WPF, установить каретку в конец каждого текстового поля и прокрутить эти позиции каретки в представлении (так что последний символ каждого текстового поля все еще отображается).

Это простая версия окна:

<Window ...>
    <StackPanel>
        <TextBox x:Name="textBox1" Text="aaabbbcccd" Height="25" Width="100" Margin="2" />
        <TextBox x:Name="textBox2" Text="aaaaabbbbbcccccd" Height="25" Width="100" Margin="2" />
        <Button Content="Switch text" Width="70" Margin="4" Click="OnClick_button_switchText" />
    </StackPanel>
</Window>

Это код для события click:

private void OnClick_button_switchText( object sender, RoutedEventArgs e )
{
     // Switch text
     string text1  = textBox1.Text;
     textBox1.Text = textBox2.Text;
     textBox2.Text = text1;

     // Scroll to last characters
     textBox1.ScrollToEnd();
     textBox2.ScrollToEnd();
}

К сожалению, ScrollToEnd() работает не так, как ожидалось: ничего не происходит. Поэтому я также попробовал несколько других возможностей, которые также ничего не делали, пока я не начал фокусироваться:

private void OnClick_button_switchText( object sender, RoutedEventArgs e )
{
    ...

    // 2nd try
    textBox1.Focus();
    textBox1.CaretIndex = textBox1.Text.Length;
    textBox2.Focus();
    textBox2.CaretIndex = textBox2.Text.Length;

    // 3rd try
    textBox1.Focus();
    EditingCommands.MoveToLineEnd.Execute( null, textBox1 );
    textBox2.Focus();
    EditingCommands.MoveToLineEnd.Execute( null, textBox2 );

    // 4th try
    textBox1.Focus();
    Rect a_charIndexRect = textBox1.GetRectFromCharacterIndex( textBox1.CaretIndex );
    textBox1.ScrollToHorizontalOffset( a_charIndexRect.Right );
    textBox2.Focus();
    a_charIndexRect = textBox2.GetRectFromCharacterIndex( textBox2.CaretIndex );
    textBox2.ScrollToHorizontalOffset( a_charIndexRect.Right );
}

Если фокус был установлен прямо перед фактическим методом прокрутки, он почти сработал (со 2-й и 3-й возможностью): textBox2 отображает текст правильно, но textBox1 до сих пор не прокручивается до конца - НО он устанавливает каретку до конца.
Если вы нажмете вкладку, чтобы сфокусировать этот элемент управления, вы заметите, что курсор находится в конце, но не отображается.

Поэтому я подумал, что это может быть какая-то проблема синхронизации, и попытался выполнить соответствующий метод прокрутки внутри события GotFocus в TextBoxes, но без каких-либо успехов.

Есть ли способ переключить текст двух текстовых полей и показывать последние символы?
Любая помощь будет оценена по достоинству.

  • 0
    «Начните использовать WPF, будет весело, - сказали они» ... Если ваша идея весело - точно знать, как работает WPF за кулисами, а затем придерживаться их идеи дизайна и никогда не отклоняться от нее. Вам, вероятно, нужно перестроить свое приложение в соответствии со стандартом MVVM, чтобы заставить это работать. На более серьезной ноте ... хотя программно изменяющий материал в WPF - это IFFY, вам может понадобиться установить фокус клавиатуры и на текстовое поле, а затем прокрутить. Возможно, вам придется подождать x кадров между действиями ... WPF никогда не задумывался о том, чтобы ppl делал вещи программно. "Будет весело и здорово, что они сказали ..."
  • 2
    К сожалению, ваш вопрос не совсем ясен относительно того, что вы ожидаете. Но ваш пример не похож на многострочное текстовое поле. если вы ожидаете, что представление TextBox будет прокручиваться горизонтально, тогда ваши ожидания неверны. Метод ScrollToEnd() прокручивает только вертикально до последней строки содержимого. Фактически, он намеренно будет прокручиваться горизонтально влево (то есть в начале) одновременно. Тем не менее, я хотел бы ожидать ScrollToHorizontalOffset(double.PositiveInfinity) работать в этом случае. Пожалуйста, уточните, что именно вы на самом деле ожидаете.
Показать ещё 3 комментария
Теги:
wpf

1 ответ

0
Лучший ответ

После нескольких попыток и намека Питера Дунихо я понял, как это сделать.
Обратите внимание, что это еще не идеальное решение, потому что это не подход MVVM, а рабочий способ сделать это.
Вы должны использовать разные методы, если вы хотите сфокусировать один из этих текстовых полей после прокрутки до конца:

private void OnClick_button_switchText( object sender, RoutedEventArgs e )
{
     // Switch text
     string text1  = textBox1.Text;
     textBox1.Text = textBox2.Text;
     textBox2.Text = text1;

     // Scroll to end - without focus
     textBox1.ScrollToHorizontalOffset( double.PositiveInfinity );
     textBox2.ScrollToHorizontalOffset( double.PositiveInfinity );

     // Scroll to end - and focus the first TextBox
     textBox1.Focus();
     EditingCommands.MoveToLineEnd.Execute( null, textBox1 );
     textBox2.ScrollToHorizontalOffset( double.PositiveInfinity );

     // Scroll to end - and focus the second TextBox
     textBox1.ScrollToHorizontalOffset( double.PositiveInfinity );
     textBox2.Focus();
     EditingCommands.MoveToLineEnd.Execute( null, textBox2 );
}

Изменение: здесь мой подход MVVM (я сохранил существующий фокус)

<Window ...>
    <StackPanel>
        <TextBox x:Name="textBox1" Text="{Binding Text1}" behaviors:TextBoxScrollToEndBehavior.ScrollToEndOnEnabledBehavior="True" Height="25" Width="100" Margin="2"/>
        <TextBox x:Name="textBox2" Text="{Binding Text2}" behaviors:TextBoxScrollToEndBehavior.ScrollToEndOnEnabledBehavior="True" Height="25" Width="100" Margin="2"/>
        <Button Content="Switch text" Width="70" Margin="4" Command="{Binding CommandSwitchText}" />
    </StackPanel>
</Window>

ViewModel:

using Behaviors;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace ViewModels
{
   class MainWindowViewModel : ObservableObject
   {
      public MainWindowViewModel()
      {
         CommandSwitchText = new RelayCommand( SwitchText );
      }


      public RelayCommand CommandSwitchText
      {
         get;
         private set;
      }


      private void SwitchText()
      {
         TextBoxScrollToEndBehavior.IsActive = true;

         string textTemp = Text1;
         Text1 = Text2;
         Text2 = textTemp;

         TextBoxScrollToEndBehavior.IsActive = false;
      }


      private string _text1 = "aaabbbcccd";
      public string Text1
      {
         get
         {
            return _text1;
         }
         set
         {
            _text1 = value;
            RaisePropertyChanged();
         }
      }


      private string _text2 = "aaaaabbbbbcccccd";
      public string Text2
      {
         get
         {
            return _text2;
         }
         set
         {
            _text2 = value;
            RaisePropertyChanged();
         }
      }
   }
}

Поведение:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace Behaviors
{
   public static class TextBoxScrollToEndBehavior
   {
      private static bool _isActive = false;
      public static bool IsActive
      {
         get
         {
            return _isActive;
         }
         set
         {
            _isActive = value;
         }
      }




      public static readonly DependencyProperty ScrollToEndOnEnabledBehavior = 
         DependencyProperty.RegisterAttached( "ScrollToEndOnEnabledBehavior",
                                              typeof( bool ),
                                              typeof( TextBoxScrollToEndBehavior ),
                                              new UIPropertyMetadata( false, OnScrollToEndOnEnabledBehavior ) );




      public static bool GetScrollToEndOnEnabledBehavior( DependencyObject obj )
      {
         return (bool)obj.GetValue( ScrollToEndOnEnabledBehavior );
      }




      public static void SetScrollToEndOnEnabledBehavior( DependencyObject obj, bool value )
      {
         obj.SetValue( ScrollToEndOnEnabledBehavior, value );
      }




      private static void OnScrollToEndOnEnabledBehavior( object sender, DependencyPropertyChangedEventArgs e )
      {
         TextBox textBox = sender as TextBox;
         if( textBox != null )
         {
            bool isEnabled = (bool)e.NewValue;
            if( isEnabled )
            {
               textBox.TextChanged += OnTextChanged_textBox;
            }
            else
            {
               textBox.TextChanged -= OnTextChanged_textBox;
            }
         }
      }




      static void OnTextChanged_textBox( object sender, TextChangedEventArgs e )
      {
         TextBox textBox = sender as TextBox;
         if( null != textBox )
         {
            if( IsActive )
            {
               if( textBox.IsFocused )
               {
                  EditingCommands.MoveToLineEnd.Execute( null, textBox );
               }
               else
               {
                  textBox.ScrollToHorizontalOffset( double.PositiveInfinity );
               }
            }
         }
      }
   }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню