Я пытаюсь переключить текст двух текстовых полей 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, но без каких-либо успехов.
Есть ли способ переключить текст двух текстовых полей и показывать последние символы?
Любая помощь будет оценена по достоинству.
После нескольких попыток и намека Питера Дунихо я понял, как это сделать.
Обратите внимание, что это еще не идеальное решение, потому что это не подход 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 );
}
}
}
}
}
}
TextBox
будет прокручиваться горизонтально, тогда ваши ожидания неверны. МетодScrollToEnd()
прокручивает только вертикально до последней строки содержимого. Фактически, он намеренно будет прокручиваться горизонтально влево (то есть в начале) одновременно. Тем не менее, я хотел бы ожидатьScrollToHorizontalOffset(double.PositiveInfinity)
работать в этом случае. Пожалуйста, уточните, что именно вы на самом деле ожидаете.