在某些位置抑制RichTextBox中的换行符

时间:2011-06-15 14:56:58

标签: c# .net richtextbox rtf line-breaks

我需要在RichTextBox中抑制一些换行符。

例如,考虑d6+6+之间不得有换行符。基本上我在HTML中寻找像<nobr>这样的东西。

到目前为止,我已经搞砸了插入\ u + FEFF等(在一些机器上工作,但有些显示垂直线,可能是字体问题,虽然windows标准字体)。我也尝试直接操纵rtf,即box.rtf = ...并在其中放置一些\zwnbo,但我似乎永远不会正确。

非常感谢。

4 个答案:

答案 0 :(得分:4)

是的,您可以将所有RichText API与RichTextBox控件一起使用。

您可能会对以下网站感兴趣:

http://www.pinvoke.net/default.aspx/user32.sendmessage - 如何使用p / invoke向Windows发送消息。

您可以使用Handle的{​​{1}}属性来获取该控件的窗口句柄,然后向其发送消息

另请查看这些包含来自Microsoft的SDK的包含文件,它们不会直接在C#中使用,但这些文件会包含您可能必须使用的所有常量,例如RichTextBox,{{1}和其他人。

  • WINUSER.H
  • richedit.h

在以下示例中我    演示如何使用API    提供。

修改

这个新示例的代码标记为不安全,但它更好,因为它没有单字符串的问题,因为我可以有一个WB_ISDELIMITER参数并对其进行操作。 旧样本遵循以下内容:

这是C#代码,而不是C ++ ...要编译它,您必须转到项目选项并将复选框标记为允许运行不安全的代码

右键单击该项目 - &gt;属性(Alt + Enter) - &gt;构建 - &gt;一般 - &gt;允许不安全的代码(必须选中)

WB_CLASSIFY

旧示例代码

该示例包含一个继承自RichTextBox的类,并使用char*放置自定义处理程序。这个类只会在超过' - '字符时完全断行。不是之前,也不是之后。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace q6359774
{
    class MyRichTextBox : RichTextBox
    {
        const int EM_SETWORDBREAKPROC = 0x00D0;
        const int EM_GETWORDBREAKPROC = 0x00D1;

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            this.Text = "abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz";
            NewMethod();
        }

        unsafe private void NewMethod()
        {
            if (!this.DesignMode)
                SendMessage(this.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, Marshal.GetFunctionPointerForDelegate(new EditWordBreakProc(MyEditWordBreakProc)));
        }

        [DllImport("User32.DLL")]
        public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

        unsafe delegate int EditWordBreakProc(char* lpch, int ichCurrent, int cch, int code);

        unsafe int MyEditWordBreakProc(char* lpch, int ichCurrent, int cch, int code)
        {
            const int WB_ISDELIMITER = 2;
            const int WB_CLASSIFY = 3;
            if (code == WB_ISDELIMITER)
            {
                char ch = *lpch;
                return ch == '-' ? 0 : 1;
            }
            else if (code == WB_CLASSIFY)
            {
                char ch = *lpch;
                var vResult = Char.GetUnicodeCategory(ch);
                return (int)vResult;
            }
            else
            {
                var lpch2 = lpch;
                // in this case, we must find the begining of a word:
                for (int it = ichCurrent; it < cch; it++)
                {
                    char ch = *lpch2;
                    if (it + 1 < cch && lpch2[0] == '-' && lpch2[1] != '-')
                        return it;
                    if (lpch2[0] == '\0')
                        return 0;
                    lpch2++;
                }
            }

            return 0;
        }
    }
}

这只是一个草案,所以你可能需要进一步改进它,这样你才能实现目标。

将控件放在窗体中,然后运行。

调整窗口大小,看看这是否是您想要做的!

你必须寻求单词边界......我还没有设法让它工作。

答案 1 :(得分:2)

我不确定,但如果RichTextBox实际上正在包装Windows丰富的编辑控件,那么通过阅读本文可能会有一些运气:

http://msdn.microsoft.com/en-us/library/hh270412%28v=vs.85%29.aspx

或更具体地说:

http://msdn.microsoft.com/en-us/library/bb787877%28v=vs.85%29.aspx

我希望这会有所帮助。

答案 2 :(得分:0)

我很快就试过这个,似乎有效:

this.userControl.richTextBox1.LoadFile("C:\\test.rtf");
this.userControl.richTextBox1.Rtf = this.userControl.richTextBox1.Rtf.Replace(@"\par", String.Empty);

this.userControl.richTextBox1.SaveFile("C:\\test2.rtf", RichTextBoxStreamType.RichText);

答案 3 :(得分:0)

这是我的解决方案(基于@Miguel Angelo,但经过修改和纠正):

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MyNameSpace
{
    public class SpaceBreakingRichTextBox : RichTextBox
    {
        const int EM_SETWORDBREAKPROC = 0x00D0;
        const int EM_GETWORDBREAKPROC = 0x00D1;

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            AddDelegate();
        }

        [DllImport("User32.DLL")]
        public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

        unsafe delegate int EditWordBreakProc(char* lpch, int ichCurrent, int cch, int code);
        EditWordBreakProc myDelegate;

        unsafe private void AddDelegate()
        {
            if (!this.DesignMode)
            {
                myDelegate = new EditWordBreakProc(MyEditWordBreakProc);
                SendMessage(this.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, Marshal.GetFunctionPointerForDelegate(myDelegate));
            }
        }

        unsafe int MyEditWordBreakProc(char* lpch, int ichCurrent, int cch, int code)
        {
            const int WB_ISDELIMITER = 2;
            const int WB_CLASSIFY = 3;
            const int WB_MOVEWORDLEFT = 4;
            const int WB_MOVEWORDRIGHT = 5;

            const int WB_LEFTBREAK = 6;
            const int WB_RIGHTBREAK = 7;

            const int WB_LEFT = 0;
            const int WB_RIGHT = 1;

            if (code == WB_ISDELIMITER)
            {
                char ch = *lpch;
                return ch == ' ' ? 1 : 0;
            }
            else if (code == WB_CLASSIFY)
            {
                char ch = *lpch;
                var vResult = Char.GetUnicodeCategory(ch);
                return (int)vResult;
            }
            else if (code == WB_LEFTBREAK)
            {
                for (int it = ichCurrent; it >= 0; it--)
                {
                    if (lpch[it] == ' '/* && lpch2[1] != ' '*/)
                    {
                        if (it > 0 && lpch[it - 1] != ' ')
                            return it;
                    }
                }
            }
            else if (code == WB_RIGHT)
            {
                for (int it = ichCurrent; ; it++)
                {
                    if (lpch[it] != ' ')
                        return it;
                }
            }
            else
            {
                 // There might be more cases to handle (see constants)
            }
            return 0;
        }
    }
}

请注意,您需要保留委托方法,否则它将从垃圾收集器收集时崩溃(这很难调试)。

基本上,这个子类只在空格处断开,这对我目前的需求来说已经足够了。