仅当文本不合适时,如何在System.Windows.Forms.TextBox上显示滚动条?
对于具有Multiline = True的System.Windows.Forms.TextBox,我只想在文本不适合时显示滚动条。
这是一个只读文本框,仅用于显示。这是一个TextBox,以便用户可以复制文本。有内置支持滚动条自动显示的功能吗?如果没有,我应该使用其他控件吗?还是我需要钩住TextChanged并手动检查是否溢出(如果是,那么如何确定文本是否适合?)
WordWrap和Scrollbars设置的各种组合没有运气。我希望最初没有滚动条,并且只有当文本不适合给定方向时,每个滚动条才会动态显示。
@nobugz,谢谢,在禁用WordWrap时可以使用。我宁愿不要禁用自动换行,但这是两种弊端中的较小者。
@Andr Neves,好点,如果它是用户可编辑的,我会采用这种方式。我同意一致性是UI直观性的基本规则。
解决方案
回答
我还进行了一些实验,发现垂直栏始终显示(如果启用),水平栏始终在启用和" WordWrap == false"的情况下始终显示。
我认为我们不会在这里得到想要的东西。但是,我相信用户希望Windows的默认行为比我们尝试强制的默认行为更好。如果我使用的是应用程序,那么我的文本框房地产突然缩水,可能仅仅是因为它需要容纳一个意外的滚动条,因为我给它提供了太多的文字,我可能会因此而烦恼!
只是让应用程序遵循Windows的外观可能是一个好主意。
回答
在项目中添加一个新类,并粘贴以下代码。编译。将新控件从工具箱的顶部拖放到窗体上。它不是很完美,但应该为我们工作。
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); } }
回答
当我想解决同样的问题时,我遇到了这个问题。
最简单的方法是更改为System.Windows.Forms.RichTextBox。在这种情况下,ScrollBars属性可以保留为RichTextBoxScrollBars.Both的默认值,该值指示"在需要时同时显示水平和垂直滚动条"。如果TextBox上提供了此功能,那就太好了。
回答
nobugz解决方案中存在一个非常细微的错误,该错误会导致堆损坏,但仅当我们使用AppendText()更新TextBox时才如此。
从OnTextChanged设置ScrollBars属性将导致Win32窗口(句柄)被破坏并重新创建。但是从Win32编辑控件(EditML_InsertText)的肠中调用OnTextChanged,此后立即期望该Win32编辑控件的内部状态不变。不幸的是,由于重新创建了窗口,因此操作系统已释放了该内部状态,从而导致访问冲突。
因此,故事的寓意是:如果要使用nobugz的解决方案,请不要使用AppendText()。
回答
我在下面的代码上取得了一些成功。
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); } }