vscrollbar visual programar net formulario ejemplos desplazamiento como barras barra winforms textbox scrollbar

winforms - visual - textbox c#



¿Cómo puedo mostrar las barras de desplazamiento en un System.Windows.Forms.TextBox solo cuando el texto no encaja? (6)

También realicé algunos experimentos y descubrí que la barra vertical siempre se mostrará si la habilita, y la barra horizontal siempre se muestra mientras esté habilitado y WordWrap == false .

Creo que no obtendrás exactamente lo que quieres aquí. Sin embargo, creo que a los usuarios les gustaría un mejor comportamiento predeterminado de Windows que el que intentas forzar. Si estuviese usando su aplicación, probablemente me molestaría si mis propiedades textbox se redujeran repentinamente solo porque necesita acomodar una barra de desplazamiento inesperada porque le di demasiado texto.

Tal vez sería una buena idea dejar que su aplicación siga el estilo de Windows.

Para un System.Windows.Forms.TextBox con Multiline = True, me gustaría mostrar solo las barras de desplazamiento cuando el texto no encaje.

Este es un cuadro de texto de solo lectura usado solo para mostrar. Es un TextBox para que los usuarios puedan copiar el texto. ¿Hay algo incorporado para admitir la exhibición automática de barras de desplazamiento? Si no, ¿debería usar un control diferente? ¿O necesito enganchar TextChanged y verificar manualmente el desbordamiento (si es así, cómo saber si el texto se ajusta?)

No tuve suerte con varias combinaciones de ajustes de WordWrap y Scrollbars. Me gustaría no tener barras de desplazamiento inicialmente y que cada una de ellas aparezca dinámicamente solo si el texto no encaja en la dirección dada.

@nobugz, gracias, que funciona cuando WordWrap está deshabilitado. Preferiría no deshabilitar la conversión de palabras, pero es el menor de dos males.

@ André Neves, buen punto, y yo iría de esa manera si fuera editable por el usuario. Estoy de acuerdo en que la coherencia es la regla cardinal para la intuición de UI.


Me encontré con esta pregunta cuando quería resolver el mismo problema.

La forma más fácil de hacerlo es cambiar a System.Windows.Forms.RichTextBox. La propiedad ScrollBars en este caso se puede dejar en el valor predeterminado de RichTextBoxScrollBars.Both, que indica "Mostrar una barra de desplazamiento horizontal y vertical cuando sea necesario". Sería bueno si esta funcionalidad se proporcionara en TextBox.


Hay un error extremadamente sutil en la solución de nobugz que da como resultado un daño en el montón, pero solo si estás usando AppendText () para actualizar el TextBox.

Configurar la propiedad ScrollBars desde OnTextChanged hará que se destruya y vuelva a crear la ventana (identificador) de Win32. Pero se llama a OnTextChanged desde las entrañas del control de edición de Win32 (EditML_InsertText), que inmediatamente después espera que el estado interno de ese control de edición de Win32 no se modifique. Desafortunadamente, desde que se recrea la ventana, ese estado interno ha sido liberado por el sistema operativo, lo que resulta en una violación de acceso.

Entonces la moraleja de la historia es: no use AppendText () si va a usar la solución de nobugz.


Tuve cierto éxito con el código a continuación.

public partial class MyTextBox : TextBox { private bool mShowScrollBar = false; public MyTextBox() { InitializeComponent(); checkForScrollbars(); } private void checkForScrollbars() { bool showScrollBar = false; int padding = (this.BorderStyle == BorderStyle.Fixed3D) ? 14 : 10; using (Graphics g = this.CreateGraphics()) { // Calcualte the size of the text area. SizeF textArea = g.MeasureString(this.Text, this.Font, this.Bounds.Width - padding); if (this.Text.EndsWith(Environment.NewLine)) { // Include the height of a trailing new line in the height calculation textArea.Height += g.MeasureString("A", this.Font).Height; } // Show the vertical ScrollBar if the text area // is taller than the control. showScrollBar = (Math.Ceiling(textArea.Height) >= (this.Bounds.Height - padding)); if (showScrollBar != mShowScrollBar) { mShowScrollBar = showScrollBar; this.ScrollBars = showScrollBar ? ScrollBars.Vertical : ScrollBars.None; } } } protected override void OnTextChanged(EventArgs e) { checkForScrollbars(); base.OnTextChanged(e); } protected override void OnResize(EventArgs e) { checkForScrollbars(); base.OnResize(e); } }


Agregue una nueva clase a su proyecto y pegue el código que se muestra a continuación. Compilar. Coloque el nuevo control desde la parte superior de la caja de herramientas en su formulario. No es perfecto, pero debería funcionar para ti.

using System; using System.Drawing; using System.Windows.Forms; public class MyTextBox : TextBox { private bool mScrollbars; public MyTextBox() { this.Multiline = true; this.ReadOnly = true; } private void checkForScrollbars() { bool scroll = false; int cnt = this.Lines.Length; if (cnt > 1) { int pos0 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(0)).Y; if (pos0 >= 32768) pos0 -= 65536; int pos1 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(1)).Y; if (pos1 >= 32768) pos1 -= 65536; int h = pos1 - pos0; scroll = cnt * h > (this.ClientSize.Height - 6); // 6 = padding } if (scroll != mScrollbars) { mScrollbars = scroll; this.ScrollBars = scroll ? ScrollBars.Vertical : ScrollBars.None; } } protected override void OnTextChanged(EventArgs e) { checkForScrollbars(); base.OnTextChanged(e); } protected override void OnClientSizeChanged(EventArgs e) { checkForScrollbars(); base.OnClientSizeChanged(e); } }


Lo que Aidan describe es casi exactamente el escenario de UI que estoy enfrentando. Como el cuadro de texto es de solo lectura, no lo necesito para responder a TextChanged. Y preferiría que el recálculo automático de desplazamiento se retrase para que no se active decenas de veces por segundo mientras se cambia el tamaño de una ventana.

Para la mayoría de las UI, los cuadros de texto con barras de desplazamiento vertical y horizontal son, bueno, malvados, así que solo me interesan las barras verticales de desplazamiento aquí.

También encontré que MeasureString produjo una altura que en realidad era más grande de lo que se requería. El uso de PreferredHeight del cuadro de texto sin borde como la altura de línea da un mejor resultado.

Lo siguiente parece funcionar bastante bien, con o sin borde, y funciona con WordWrap activado.

Simplemente llame a AutoScrollVertically () cuando lo necesite y, opcionalmente, especifique recalculateOnResize.

public class TextBoxAutoScroll : TextBox { public void AutoScrollVertically(bool recalculateOnResize = false) { SuspendLayout(); if (recalculateOnResize) { Resize -= OnResize; Resize += OnResize; } float linesHeight = 0; var borderStyle = BorderStyle; BorderStyle = BorderStyle.None; int textHeight = PreferredHeight; try { using (var graphics = CreateGraphics()) { foreach (var text in Lines) { var textArea = graphics.MeasureString(text, Font); if (textArea.Width < Width) linesHeight += textHeight; else { var numLines = (float)Math.Ceiling(textArea.Width / Width); linesHeight += textHeight * numLines; } } } if (linesHeight > Height) ScrollBars = ScrollBars.Vertical; else ScrollBars = ScrollBars.None; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); } finally { BorderStyle = borderStyle; ResumeLayout(); } } private void OnResize(object sender, EventArgs e) { m_timerResize.Stop(); m_timerResize.Tick -= OnDelayedResize; m_timerResize.Tick += OnDelayedResize; m_timerResize.Interval = 475; m_timerResize.Start(); } Timer m_timerResize = new Timer(); private void OnDelayedResize(object sender, EventArgs e) { m_timerResize.Stop(); Resize -= OnResize; AutoScrollVertically(); Resize += OnResize; } }