在我的windows.forms c#应用程序中,我有一个WordWrap = true的多行文本框。在我将Text属性设置为长字符串后,我需要通过包装生成所有行。它与Lines []属性不同,因为我的文本不包含换行符。 我找到了使用图形MeasureString函数的解决方案,但考虑到文本框控件已经完成了包装,它似乎有点额外的工作 - 为什么我应该再做同样的工作? 有没有办法获得文本框包装文本的行?
谢谢
答案 0 :(得分:5)
您可以查看以下解决方案,
public Form1()
{
InitializeComponent();
textBox1.Text = "This is my text where I want to check how I can get wrapped content as seperate lines automatically !! This is my text which I want to check how I can get wrapped content as seperate lines automatically !!";
}
private void button1_Click(object sender, EventArgs e)
{
bool continueProcess = true;
int i = 1; //Zero Based So Start from 1
int j = 0;
List<string> lines = new List<string>();
while (continueProcess)
{
var index = textBox1.GetFirstCharIndexFromLine(i);
if (index != -1)
{
lines.Add(textBox1.Text.Substring(j, index - j));
j = index;
i++;
}
else
{
lines.Add(textBox1.Text.Substring(j, textBox1.Text.Length - j));
continueProcess = false;
}
}
foreach(var item in lines)
{
MessageBox.Show(item);
}
}
GetFirstCharIndexFromLine Reference
文本框中的行编号从零开始。如果是lineNumber 参数大于文本框中的最后一行, GetFirstCharIndexFromLine返回-1。
GetFirstCharIndexFromLine返回a的第一个字符索引 物理线。物理线是显示的线,而不是 分配线。显示的行数可以大于 由于自动换行而分配的行数。例如,如果您指定 两个长行到RichTextBox控件并设置Multiline和WordWrap 为true,两个长指定的行导致四个物理(或 显示的行)。
答案 1 :(得分:1)
我再次检查了Win32 API并意识到它可以轻松完成。我写了一个扩展方法,所以你可以更容易地做到:
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class TextBoxExtensions
{
private const uint EM_FMTLINES = 0x00C8;
private const uint WM_GETTEXT = 0x000D;
private const uint WM_GETTEXTLENGTH = 0x000E;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
public static string[] GetWrappedLines(this TextBox textBox)
{
var handle = textBox.Handle;
SendMessage(handle, EM_FMTLINES, 1, IntPtr.Zero);
var size = SendMessage(handle, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero).ToInt32();
if (size > 0)
{
var builder = new StringBuilder(size + 1);
SendMessage(handle, WM_GETTEXT, builder.Capacity, builder);
return builder.ToString().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
}
return new string[0];
}
}
}
用法:
var lines = textBox1.GetWrappedLines();
WinForm TextBox实际上是Windows GDI编辑控件的包装器,它本身处理文本换行。话虽这么说,即使TextBox保留了一系列包装线,它也不会被公共API暴露,甚至不会被带到托管环境(如果确实如此,它可以通过反射检索)。所以你最好的选择仍然是MeasureString。
答案 2 :(得分:1)
有点刺激可行:
private const UInt32 EM_GETLINECOUNT = 0xba;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private void button1_Click(object sender, EventArgs e) {
int numLines = SendMessage(textBox1.Handle,
EM_GETLINECOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32()
MessageBox.Show(numLines.ToString());
}
答案 3 :(得分:0)
To check if particular line is wrapped or not, here is the GDI Function you need to use:
1. [DllImport("user32.dll")]
static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Dimension lpRect, int wFormat);
Here are what you need to get things done:
public enum DrawTextFlags
{
CalculateArea = 0x00000400,
WordBreak = 0x00000010,
TextBoxControl = 0x00002000,
Top = 0x00000000,
Left = 0x00000000,
HorizontalCenter = 0x00000001,
Right = 0x00000002,
VerticalCenter = 0x00000004,
Bottom = 0x00000008,
SingleLine = 0x00000020,
ExpandTabs = 0x00000040,
TabStop = 0x00000080,
NoClipping = 0x00000100,
ExternalLeading = 0x00000200,
NoPrefix = 0x00000800,
Internal = 0x00001000,
PathEllipsis = 0x00004000,
EndEllipsis = 0x00008000,
WordEllipsis = 0x00040000,
ModifyString = 0x00010000,
RightToLeft = 0x00020000,
NoFullWidthCharacterBreak = 0x00080000,
HidePrefix = 0x00100000,
PrefixOnly = 0x00200000,
NoPadding = 0x10000000,
}
[StructLayout(LayoutKind.Sequential)]
public struct Dimension
{
public int Left, Top, Right, Bottom;
public Dimension(int left, int top, int right, int bottom)
{
this.Left = left;
this.Right = right;
this.Top = top;
this.Bottom = bottom;
}
public Dimension(Rectangle r)
{
this.Left = r.Left;
this.Top = r.Top;
this.Bottom = r.Bottom;
this.Right = r.Right;
}
public static implicit operator Rectangle(Dimension rc)
{
return Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom);
}
public static implicit operator Dimension(Rectangle rc)
{
return new Dimension(rc);
}
public static Dimension Default
{
get { return new Dimension(0, 0, 1, 1); }
}
}
So to know whether a particular line is wrapped or not, you would call the function like this:
Dimension rc = new Dimension(0,0,2,2);
var flag = DrawTextFlags.CalculateArea | DrawTextFlags.TextBoxControl | DrawTextFlags.WordBreak;
DrawText(hdc, line, line.length, ref rc, (int)flag);
Now if height of rc you get after executing this function is greater then your font height or tmHeight if you use TextMetric (that is what minimum required for a line to fit vertically) you can safely assume your line is wrapped.
Apart from this,
You can use the following function as an alternative approach:
static extern bool GetTextExtentExPoint(IntPtr hDc, string str, int nLength,
int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size);