wpf - Cuadro de texto multilínea con desplazamiento vertical automático
textbox multiline (4)
Hay muchas preguntas similares sobre Internet, incluidas SO, pero las soluciones propuestas no funcionan en mi caso. Escenario: hay un cuadro de texto de registro en xaml
<TextBox Name="Status"
Margin="5"
Grid.Column="1"
Grid.Row="5"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="600"
Height="310"/>
Hay métodos en el código subyacente que hacen un poco de trabajo y agregan algunos mensajes de varias líneas (¿quizás ese es el problema?) En este cuadro de texto:
private static void DoSomeThings(TextBox textBox)
{
// do work
textBox.AppendText("Work finished/r/n"); // better way than Text += according to msdn
// do more
textBox.AppendText("One more message/r/n");
...
}
private static void DoSomething2(TextBox textBox)
{
// same as first method
}
Necesitas desplazarte a la parte inferior del cuadro de texto después de que todas las acciones tengan lugar. Probé ScrollToEnd (), ScrollToLine, envolviendo textbox en ScrollViewer, Selection y Caret workarounds, adjuntando ScrollToEnd a TextChanged. Nada de esto funciona, después de que las líneas de ejecución que desbordan la altura del cuadro de texto todavía tienen que desplazarse manualmente. Perdón por la pregunta duplicada, creo que me faltan algunos problemas menores que pueden ser resueltos rápidamente por alguien que tenga una nueva visión del problema. Gracias por adelantado.
¡Gracias! He agregado esto para recordar el enfoque original:
var oldFocusedElement = FocusManager.GetFocusedElement(this);
this.textBox.Focus();
this.textBox.CaretIndex = this.textBox.Text.Length;
this.textBox.ScrollToEnd();
FocusManager.SetFocusedElement(this, oldFocusedElement);
De acuerdo con esta pregunta: TextBox.ScrollToEnd no funciona cuando el TextBox está en una pestaña no activa
Tienes que enfocar el cuadro de texto, actualizar la posición de intercalación y luego desplazarte hasta el final:
Status.Focus();
Status.CaretIndex = Status.Text.Length;
Status.ScrollToEnd();
EDITAR
Ejemplo TextBox:
<TextBox TextWrapping="Wrap" VerticalScrollBarVisibility="Auto"
AcceptsReturn="True" Name="textBox"/>
Si lo convierte en un control personalizado simple, entonces no necesita ningún código para hacer el desplazamiento.
public class ScrollingTextBox : TextBox {
protected override void OnInitialized (EventArgs e) {
base.OnInitialized(e);
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
}
protected override void OnTextChanged (TextChangedEventArgs e) {
base.OnTextChanged(e);
CaretIndex = Text.Length;
ScrollToEnd();
}
}
Si está utilizando WPF, sería mucho mejor utilizar el enlace en lugar de pasar el cuadro de texto en el código subyacente.
Si no te gusta el código detrás de mucho, aquí hay una propiedad adjunta que hará el truco:
namespace YourProject.YourAttachedProperties
{
public class TextBoxAttachedProperties
{
public static bool GetAutoScrollToEnd(DependencyObject obj)
{
return (bool)obj.GetValue(AutoScrollToEndProperty);
}
public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
{
obj.SetValue(AutoScrollToEndProperty, value);
}
// Using a DependencyProperty as the backing store for AutoScrollToEnd. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AutoScrollToEndProperty =
DependencyProperty.RegisterAttached("AutoScrollToEnd", typeof(bool), typeof(TextBoxAttachedProperties), new PropertyMetadata(false, AutoScrollToEndPropertyChanged));
private static void AutoScrollToEndPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if(d is TextBox textbox && e.NewValue is bool mustAutoScroll)
{
textbox.TextChanged += (s, ee)=> AutoScrollToEnd(s, ee, textbox);
}
}
private static void AutoScrollToEnd(object sender, TextChangedEventArgs e, TextBox textbox)
{
textbox.ScrollToEnd();
}
}
}
Y luego en tu xaml simplemente hazlo:
<TextBox
AcceptsReturn="True"
myAttachedProperties:TextBoxAttachedProperties.AutoScrollToEnd="True"/>
No olvides agregar en la parte superior de tu archivo xaml
xmlns:myAttachedProperties="clr-namespace:YourProject.YourAttachedProperties"
Y voilá