当我点击它时文本框固定到顶部
Textbox pin to top when i click on it
我有一个简单的文本框:
<TextBox Name="PART_txtBx" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Auto" />
我每次都在代码隐藏中添加一些文本:
public MainWindow()
{
InitializeComponent();
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(100);
dt.Tick += dt_Tick;
dt.Start();
}
void dt_Tick(object sender, EventArgs e)
{
PART_txtBx.Text += "hi\n";
}
当我点击文本框时,当我向其中添加一些文本时,它会自动将滚动条置于顶部。
如果我这样处理 PreviewMouseLeftButtonDown 事件:
private void PART_txtBx_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
文本框可以正常工作,但我不能(当然)select任何文本。
有什么想法可以防止这种行为?
编辑 1:
我注意到在创建文本框时,即使它获得了焦点,它也没有任何插入符号。插入符号仅在执行单击时显示,但我无法找到单击后文本框中的更改内容。
我的文本框是只读的,所以我不需要插入符号。
5 月:PART_txtBx.CaretIndex =PART_txtBx.Length;
或:
PART_txtBx.SelectionStart = PART_txtBx.Text.Length;
PART_txtBx.ScrollToCaret();
ScrollToEnd().
与 textbox_changed 事件
- 您需要扩展您的 TextBox 控件以添加 PreviewTextChanged 事件,如 here 所述。在 PreviewTextChanged 上,您必须记住 SelectionStart 和 SelectionLength
为您的 TextBox 处理事件 ScrollViewer.ScrollChanged:
ScrollViewer.ScrollChanged="OnScrollChanged" <!--in xaml-->
private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
// here you could prevent scrolling
isOnBottom = (sender as TextBox).VerticalOffset + (sender as TextBox).ViewportHeight == (sender as TextBox).ExtentHeight;
}
处理 TextChanged 事件:
TextChanged="OnTextChanged"
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
if (isOnBottom) (sender as TextBox).ScrollToEnd();
// and here you can select text that was selected earlier
// by using remembered SelectionStart and SelectionLength
}
在手动输入文本的情况下,您将不得不阻止文本选择
希望,有帮助
所以我创建了自己的 CustomTextblock 来解决这个问题:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace CE.EthernetMessagesManager.Views
{
public class CustomTextBox : TextBox
{
private int realCaretIndex = 0;
private bool triggeredByUser = false;
private bool isScrollingWithMouse = false;
public CustomTextBox()
: base()
{
this.PreviewMouseLeftButtonDown += CustomTextBox_PreviewMouseLeftButtonDown;
this.PreviewMouseLeftButtonUp += CustomTextBox_PreviewMouseLeftButtonUp;
this.PreviewMouseMove += CustomTextBox_PreviewMouseMove;
this.PreviewMouseWheel += CustomTextBox_PreviewMouseWheel;
this.TextChanged += CustomTextBox_TextChanged;
this.LostFocus += CustomTextBox_LostFocus;
this.AddHandler(ScrollViewer.ScrollChangedEvent, new RoutedEventHandler((X, S) =>
{
if ((S as ScrollChangedEventArgs).VerticalChange != 0 && triggeredByUser)
{
TextBox textBox = (X as TextBox);
int newLinePosition = 0;
newLinePosition = (int)(((S as ScrollChangedEventArgs).VerticalChange + textBox.ExtentHeight) / (textBox.FontSize + 2));
realCaretIndex += newLinePosition * ((S as ScrollChangedEventArgs).VerticalChange < 0 ? -1 : 1);
if (realCaretIndex < 0)
realCaretIndex = 0;
textBox.CaretIndex = realCaretIndex;
triggeredByUser = false;
}
}));
}
void CustomTextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
e.Handled = true;
}
void CustomTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
textBox.CaretIndex = realCaretIndex;
var max = (textBox.ExtentHeight - textBox.ViewportHeight);
var offset = textBox.VerticalOffset;
if (max != 0 && max == offset)
this.Dispatcher.Invoke(new Action(() =>
{
textBox.ScrollToEnd();
}),
System.Windows.Threading.DispatcherPriority.Loaded);
}
void CustomTextBox_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
triggeredByUser = true;
}
void CustomTextBox_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (isScrollingWithMouse)
{
TextBox textBox = sender as TextBox;
realCaretIndex = textBox.GetCharacterIndexFromPoint(Mouse.GetPosition(textBox), true);
}
}
void CustomTextBox_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
isScrollingWithMouse = false;
}
void CustomTextBox_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
TextBox textBox = sender as TextBox;
realCaretIndex = textBox.GetCharacterIndexFromPoint(Mouse.GetPosition(textBox), true);
triggeredByUser = true;
isScrollingWithMouse = true;
}
}
}
当我手动将滚动条置于底部时,此 CustomTextBox 也将滚动条固定在底部。
xaml:
<v:CustomTextBox
IsReadOnly="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
/>
遗憾的是,这个实现选择被破坏了。我会调查一下
我有一个简单的文本框:
<TextBox Name="PART_txtBx" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Auto" />
我每次都在代码隐藏中添加一些文本:
public MainWindow()
{
InitializeComponent();
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(100);
dt.Tick += dt_Tick;
dt.Start();
}
void dt_Tick(object sender, EventArgs e)
{
PART_txtBx.Text += "hi\n";
}
当我点击文本框时,当我向其中添加一些文本时,它会自动将滚动条置于顶部。
如果我这样处理 PreviewMouseLeftButtonDown 事件:
private void PART_txtBx_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
文本框可以正常工作,但我不能(当然)select任何文本。
有什么想法可以防止这种行为?
编辑 1: 我注意到在创建文本框时,即使它获得了焦点,它也没有任何插入符号。插入符号仅在执行单击时显示,但我无法找到单击后文本框中的更改内容。 我的文本框是只读的,所以我不需要插入符号。
5 月:PART_txtBx.CaretIndex =PART_txtBx.Length;
或:
PART_txtBx.SelectionStart = PART_txtBx.Text.Length;
PART_txtBx.ScrollToCaret();
ScrollToEnd(). 与 textbox_changed 事件
- 您需要扩展您的 TextBox 控件以添加 PreviewTextChanged 事件,如 here 所述。在 PreviewTextChanged 上,您必须记住 SelectionStart 和 SelectionLength
为您的 TextBox 处理事件 ScrollViewer.ScrollChanged:
ScrollViewer.ScrollChanged="OnScrollChanged" <!--in xaml--> private void OnScrollChanged(object sender, ScrollChangedEventArgs e) { // here you could prevent scrolling isOnBottom = (sender as TextBox).VerticalOffset + (sender as TextBox).ViewportHeight == (sender as TextBox).ExtentHeight; }
处理 TextChanged 事件:
TextChanged="OnTextChanged" private void OnTextChanged(object sender, TextChangedEventArgs e) { if (isOnBottom) (sender as TextBox).ScrollToEnd(); // and here you can select text that was selected earlier // by using remembered SelectionStart and SelectionLength }
在手动输入文本的情况下,您将不得不阻止文本选择
希望,有帮助
所以我创建了自己的 CustomTextblock 来解决这个问题:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace CE.EthernetMessagesManager.Views
{
public class CustomTextBox : TextBox
{
private int realCaretIndex = 0;
private bool triggeredByUser = false;
private bool isScrollingWithMouse = false;
public CustomTextBox()
: base()
{
this.PreviewMouseLeftButtonDown += CustomTextBox_PreviewMouseLeftButtonDown;
this.PreviewMouseLeftButtonUp += CustomTextBox_PreviewMouseLeftButtonUp;
this.PreviewMouseMove += CustomTextBox_PreviewMouseMove;
this.PreviewMouseWheel += CustomTextBox_PreviewMouseWheel;
this.TextChanged += CustomTextBox_TextChanged;
this.LostFocus += CustomTextBox_LostFocus;
this.AddHandler(ScrollViewer.ScrollChangedEvent, new RoutedEventHandler((X, S) =>
{
if ((S as ScrollChangedEventArgs).VerticalChange != 0 && triggeredByUser)
{
TextBox textBox = (X as TextBox);
int newLinePosition = 0;
newLinePosition = (int)(((S as ScrollChangedEventArgs).VerticalChange + textBox.ExtentHeight) / (textBox.FontSize + 2));
realCaretIndex += newLinePosition * ((S as ScrollChangedEventArgs).VerticalChange < 0 ? -1 : 1);
if (realCaretIndex < 0)
realCaretIndex = 0;
textBox.CaretIndex = realCaretIndex;
triggeredByUser = false;
}
}));
}
void CustomTextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
e.Handled = true;
}
void CustomTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
textBox.CaretIndex = realCaretIndex;
var max = (textBox.ExtentHeight - textBox.ViewportHeight);
var offset = textBox.VerticalOffset;
if (max != 0 && max == offset)
this.Dispatcher.Invoke(new Action(() =>
{
textBox.ScrollToEnd();
}),
System.Windows.Threading.DispatcherPriority.Loaded);
}
void CustomTextBox_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
triggeredByUser = true;
}
void CustomTextBox_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (isScrollingWithMouse)
{
TextBox textBox = sender as TextBox;
realCaretIndex = textBox.GetCharacterIndexFromPoint(Mouse.GetPosition(textBox), true);
}
}
void CustomTextBox_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
isScrollingWithMouse = false;
}
void CustomTextBox_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
TextBox textBox = sender as TextBox;
realCaretIndex = textBox.GetCharacterIndexFromPoint(Mouse.GetPosition(textBox), true);
triggeredByUser = true;
isScrollingWithMouse = true;
}
}
}
当我手动将滚动条置于底部时,此 CustomTextBox 也将滚动条固定在底部。 xaml:
<v:CustomTextBox
IsReadOnly="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
/>
遗憾的是,这个实现选择被破坏了。我会调查一下