То, что описывает Эйдан, является почти точно сценарием пользовательского интерфейса, с которым я сталкиваюсь. Поскольку текстовое поле доступно только для чтения, мне не нужно, чтобы оно отвечало на TextChanged. И я бы предпочел, чтобы пересчет автопрокрутки был отложен, чтобы он не срабатывал десятки раз в секунду во время изменения размера окна.
Для большинства пользовательских интерфейсов текстовые поля с вертикальной и горизонтальной полосами прокрутки, ну, в общем, зло, поэтому меня интересуют только вертикальные полосы прокрутки здесь.
Я также обнаружил, что MeasureString создает высоту, которая на самом деле была больше, чем требовалось. Использование PreferredHeight в текстовом поле без рамки, поскольку высота линии дает лучший результат.
Кажется, что следующее работает очень хорошо, с рамкой или без, и работает с WordWrap.
Просто вызовите AutoScrollVertically (), когда вам это нужно, и при необходимости укажите 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;
}
}