如何用TextBox.GetPositionFromCharIndex按需显示垂直滚动条及方法异常排查
Fixing Physical Line Counting with
GetPositionFromCharIndex and Scrollbar Visibility for WinForms TextBox Let's break down why your second method fails with just "\r\n" and how to fix it, plus handle scrollbar visibility correctly.
Why NumberOfPhysicalLinesInTextBox_2 Fails for "\r\n"
When you have only "\r\n" in the TextBox:
- The
'\r'(index 0) and'\n'(index 1) are treated as a single newline by the WinForms TextBox. Their drawn positions share the same Y-coordinate because they don't occupy separate vertical space on their own—they act as a single marker to move to the next line. - This means
lastCharY - firstCharYequals 0, so your calculation gives1 + 0 = 1instead of the correct 2 lines.
Corrected Method for Physical Line Count
Here's an adjusted version that handles edge cases like pure newlines, empty text, and standard content:
internal static int NumberOfPhysicalLinesInTextBox_Fixed(TextBox tb) { // Handle empty text case first if (string.IsNullOrEmpty(tb.Text)) return 0; int lines = 1; int firstCharY = tb.GetPositionFromCharIndex(0).Y; int lastCharIndex = tb.Text.Length - 1; int lastCharY = tb.GetPositionFromCharIndex(lastCharIndex).Y; // Calculate base line difference int lineHeight = tb.Font.Height; lines += (lastCharY - firstCharY) / lineHeight; // Special case: check if the last character is a newline (or part of one) // and if the cursor is on a new line after it char lastChar = tb.Text[lastCharIndex]; if ((lastChar == '\n' || lastChar == '\r') && tb.GetFirstCharIndexFromLine(lines) != -1) { lines++; } // Fallback to the first method's logic for edge cases to ensure accuracy int fallbackLineCount = 0; while (tb.GetFirstCharIndexFromLine(fallbackLineCount) != -1) { fallbackLineCount++; } return Math.Max(lines, fallbackLineCount); }
Key Fixes:
- Empty Text Handling: Returns 0 immediately instead of incorrect values.
- Newline Edge Case: Checks if the last character is a newline and verifies if there's an extra line after it using
GetFirstCharIndexFromLine. - Fallback Logic: Leverages your original reliable method as a safety net to cover edge scenarios where position-based calculation might fall short.
Handling Vertical Scrollbar Visibility
To show the vertical scrollbar only when needed:
- Calculate the total physical lines using the fixed method above.
- Get the number of visible lines in the TextBox (based on control height and font size):
internal static int GetVisibleLineCount(TextBox tb) { // Calculate usable client height by subtracting padding int clientHeight = tb.ClientSize.Height - tb.Padding.Top - tb.Padding.Bottom; return clientHeight / tb.Font.Height; } - Toggle the scrollbar based on line count comparison:
internal void UpdateVerticalScrollbar(TextBox tb) { int totalLines = NumberOfPhysicalLinesInTextBox_Fixed(tb); int visibleLines = GetVisibleLineCount(tb); // Show scrollbar if total lines exceed visible lines tb.ScrollBars = totalLines > visibleLines ? ScrollBars.Vertical : ScrollBars.None; }
Notes:
- Call
UpdateVerticalScrollbarwhenever the TextBox content changes (e.g., in theTextChangedevent) or when the control is resized. - Ensure the TextBox's
Multilineproperty is set totruefor scrollbars to function properly.
内容的提问来源于stack exchange,提问作者silviubogan
相关产品推荐
相关产品推荐

