在富文本框中包装文本,但不包装它

时间:2010-10-15 02:15:46

标签: c# .net winforms richtextbox word-wrap

我在窗体上有一个带有Rich Textbox控件的Windows窗体。我想要做的是使每行只接受32个字符的文本。在32个字符之后,我希望文本流到下一行(我不想插入任何回车符)。 WordWrap属性几乎可以执行此操作,除了它将所有输入的文本移动到文本中的最后一个空格并将其全部移动。我只想在32个字符后整齐地包裹文本。我怎样才能做到这一点?我正在使用C#。

4 个答案:

答案 0 :(得分:4)

好的,我已经找到了一种方法(在经过大量的谷歌搜索和Windows API引用之后),我在这里发布一个解决方案,以防其他任何人需要解决这个问题。没有干净的.NET解决方案,但幸运的是,Windows API允许您覆盖处理自动换行时调用的默认过程。首先,您需要导入以下DLL:

[DllImport("user32.dll")]

    extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

然后你需要定义这个常量:

 const uint EM_SETWORDBREAKPROC = 0x00D0;

然后创建一个委托和事件:

    delegate int EditWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);

    event EditWordBreakProc myCallBackEvent;

然后创建我们的新函数来处理自动换行(在这种情况下我不希望它做任何事情):

     private int myCallBack(IntPtr text, int pos_in_text, int bCharSet, int action)

    {

        return 0;

    }

最后,在表格的已显示事件中:

        myCallBackEvent = new EditWordBreakProc(myCallBack);

        IntPtr ptr_func = Marshal.GetFunctionPointerForDelegate(myCallBackEvent);

        SendMessage(txtDataEntry.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, ptr_func);

答案 1 :(得分:2)

如果在富文本框中仅为文本使用(一个)固定宽度字体,则可以使用MeasureString计算32个字符所需的宽度,然后相应地调整富文本框宽度。这应该包装在32个字符以内。

答案 2 :(得分:0)

我自己一直在研究这个问题,并找到了解决这个问题的简单方法。您需要在TextBox或RichTextBox控件的Key_Down事件中放置一小段代码。

确保Word Wrap和Multiline属性仍然设置为true,然后,您只需要检查KeyCode的Key Press.Return& Keycode.Enter。

如下所示: -

private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
            {
                e.Handled = true;
            }

        }

将此处理的值设置为true,发回我们处理过按键事件的消息,但没有任何反应。文本控件继续使用Word Wrap并阻止回车。

希望这会有所帮助。

答案 3 :(得分:0)

可接受的答案几乎可行,但由于不必要使用event,显式委托实例化和非静态回调方法而有些尴尬。

我说“几乎”是因为它还有一个微妙的错误:为回调创建的委托没有存储在任何变量中,这使其可以进行垃圾回收。垃圾收集器没有任何办法知道您已将委托包装指针指向窗口对象,因此最终将能够丢弃委托,这将导致应用程序崩溃。下次TextBox控件需要包装任何文本。

以下是我更喜欢的版本:

public partial class Form1 : Form
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]

    extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

    private const uint EM_SETWORDBREAKPROC = 0x00D0;

    private delegate int SetWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);
    private readonly SetWordBreakProc _wordBreakCallback = (text, pos_in_text, bCharSet, action) => 0;

    public Form1()
    {
        InitializeComponent();
        textBox1.HandleCreated += TextBox1_HandleCreated;
    }

    private void TextBox1_HandleCreated(object sender, EventArgs e)
    {
        IntPtr callback = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_wordBreakCallback);

        SendMessage(((Control)sender).Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, callback);
    }
}

这里的另一个区别是,我在TextBox.HandleCreated事件处理程序中初始化了断字proc。这完成了两件事:首先,在控件的句柄有效之后立即进行初始化;其次,如果已经设置了TextBox.Text属性,例如在在设计器或表单的构造函数中,即使对于该初始文本,换行仍将正确完成。

稍后粘贴的文本仍然可以,当然,您甚至可以在初始化后临时重置文本以强制重新包装。但是恕我直言,最好首先让它足够早地开始工作。

还要注意,以上要求对您添加到表单中的每个TextBox进行显式初始化。显然,如果您想将此技术应用于多个TextBox,则有必要创建一个新的TextBox子类,该子类将在自己的OnHandleCreated()覆盖方法中进行初始化。