C#删除行后在RichTextBox中丢失字体样式

C#删除行后在RichTextBox中丢失字体样式,c#,winforms,visual-studio,C#,Winforms,Visual Studio,我有一个RichTextBox用于简单的聊天,通过编程方式添加行。 我将用户名设置为粗体,并将消息设置为常规样式。 在几行之后,我想删除第一行,以使聊天保持在可接受的长度。但当我这样做时,我会丢失文本格式,所有内容都显示为粗体。我做错了什么?我怎样才能解决这个问题 编辑 我可以解决无法删除第一行的问题。 我必须将只读属性设置为false。即使我能够添加新行,它也阻止删除行。因此,下面的代码用于删除行。感谢@TaW if (ChatText.Lines.Length >= 10) {

我有一个
RichTextBox
用于简单的聊天,通过编程方式添加行。 我将用户名设置为粗体,并将消息设置为常规样式。 在几行之后,我想删除第一行,以使聊天保持在可接受的长度。但当我这样做时,我会丢失文本格式,所有内容都显示为粗体。我做错了什么?我怎样才能解决这个问题

编辑

我可以解决无法删除第一行的问题。 我必须将
只读属性设置为false。即使我能够添加新行,它也阻止删除行。因此,下面的代码用于删除行。感谢@TaW

if (ChatText.Lines.Length >= 10)
{
    int p = 0; int count = 0;
    do
    {
        p = ChatText.Text.IndexOf("\n\r");
        if (p >= 0)
        {
            ChatText.SelectionStart = p;
            ChatText.SelectionLength = 2; // length of "\n\r"
            ChatText.SelectedText = "\n";
            count++;
        }
    }
    while(p >= 0);

    int nll = 1;  // <<===  pick the length of your new line character(s)!!
    int pS = ChatText.Lines.Take(0).Select(x => x.Length + nll).Sum() - nll;
    int pL = ChatText.Lines.Take(1).Select(x => x.Length + nll).Sum() - nll;
    if (pS < 0) { pS = 0; pL++; }
    ChatText.SelectionStart = pS;
    ChatText.SelectionLength = pL - pS;
    ChatText.Cut();
}
//////////////////////////////////
// now add new lines
//////////////////////////////////
string[] chatstr;
// string text is given as method parameter
chatstr = text.Split(new string[] { ": " }, 2, StringSplitOptions.None);
// go to the end of the text
ChatText.SelectionStart = ChatText.Text.Length;
ChatText.SelectionLength = 0;
// make text bold
ChatText.SelectionFont = new Font(ChatText.Font, FontStyle.Bold);
// add username (chatstr[0]) and colon
ChatText.AppendText(chatstr[0] + ": ");
// make text regular
ChatText.SelectionFont = new Font(ChatText.Font, FontStyle.Regular);
// add message (chatstr[1])
ChatText.AppendText(chatstr[1] + "\n");
// and finaly scroll down
ChatText.ScrollToCaret();
if(ChatText.Lines.Length>=10)
{
int p=0;int count=0;
做
{
p=ChatText.Text.IndexOf(“\n\r”);
如果(p>=0)
{
chatterxt.SelectionStart=p;
ChatterText.SelectionLength=2;//长度为“\n\r”
ChatterText.SelectedText=“\n”;
计数++;
}
}
而(p>=0);
int nll=1;//x.Length+nll).Sum()-nll;
如果(pS<0){pS=0;pL++;}
chatterxt.SelectionStart=pS;
chatterxt.SelectionLength=pL-pS;
ChatText.Cut();
}
//////////////////////////////////
//现在添加新行
//////////////////////////////////
字符串[]chatstr;
//字符串文本作为方法参数提供
chatstr=text.Split(新字符串[]{“},2,StringSplitOptions.None);
//转到课文末尾
ChatText.SelectionStart=ChatText.Text.Length;
ChatText.SelectionLength=0;
//使文本加粗
ChatText.SelectionFont=新字体(ChatText.Font,FontStyle.Bold);
//添加用户名(chatstr[0])和冒号
AppendText(chatstr[0]+“:”);
//使文本规则化
ChatText.SelectionFont=新字体(ChatText.Font、FontStyle.Regular);
//添加消息(chatstr[1])
ChatText.AppendText(chatstr[1]+“\n”);
//最后向下滚动
ChatText.ScrollToCaret();
因此,删除行将起作用,并按预期添加新行。终于


已解决:)如果
RichtTextBox
包含任何格式,则从不更改其
文本

更改
属性(通过
跳过
)只是更改
文本
的另一种方法

相反,只使用RTB提供的功能:始终从选择要格式化的部分开始,然后应用一个或多个功能和/或设置一个或多个属性

删除部分,请使用
剪切

下面是一个函数,它将删除许多整行:

void DeleteLines(RichTextBox rtb, int fromLine, int count)
{
    int p1 = rtb.GetFirstCharIndexFromLine(fromLine);
    int p2 = rtb.GetFirstCharIndexFromLine(fromLine + count);

    rtb.SelectionStart = p1;
    rtb.SelectionLength = p2 - p1;

    bool readOnly = rtb.ReadOnly;  // allow change even when the RTB is readonly
    rtb.ReadOnly = false; ;
    rtb.Cut();
    rtb.ReadOnly = readOnly;
}
试图自己保持格式化是一种乏味且容易出错的浪费时间的行为

除了字体属性外,您还必须重新设置所有其他可以使用
SelectedXXX
属性设置的内容,如颜色、对齐方式、间距等

要删除前3行,请使用:

DeleteLines(yourRTB, 0, 3);
DeleteLines(yourRTB, 0, yourRTB.Lines.Length - 10);
要将文本限制为10行,请使用:

DeleteLines(yourRTB, 0, 3);
DeleteLines(yourRTB, 0, yourRTB.Lines.Length - 10);
注意,上面的函数应该有一些有效输入的检查;我忽略了它们,因为检查不知何故需要决定怎么做,如果
count
fromLine
大于
行。Length
fromLine
为负数

当我们进行此操作时,下面是如何添加粗体行:

yourRTB.SelectionStart = yourRTB.Text.Length;
yourRTB.SelectionLength = 0;
using (Font font = new Font(yourRTB.SelectionFont, FontStyle.Bold))
    yourRTB.SelectionFont = font;
yourRTB.AppendText(yourNewLine + textOfNewLine);
当然,它真的应该进入一个可重用的函数,将粗体作为一个参数

更新:

由于您使用的是
WordWrap
,因此您可能更喜欢此功能。它将删除实际行,而不是可见行:

void DeleteLinesWW(RichTextBox rtb, int fromLine, int count)
{
    int nll = 1;  // <<===  pick the length of your new line character(s)!!
    int pS = rtb.Lines.Take(fromLine).Select(x => x.Length + nll).Sum() - nll;
    int pL = rtb.Lines.Take(fromLine + count).Select(x => x.Length + nll).Sum() - nll;
    if (pS < 0) { pS = 0; pL++; }
    rtb.SelectionStart = pS;
    rtb.SelectionLength = pL - pS ;

    bool readOnly = rtb.ReadOnly;
    rtb.ReadOnly = false;   // allow change even when the RTB is readonly
    rtb.Cut();
    rtb.ReadOnly = readOnly;  
  }
这样称呼:

RTBReplace(yourrichTextBox, "\r\n", "\n");
更新2:

下面是一个如何添加聊天线路的示例:

private void button1_Click(object sender, EventArgs e)
{
    string cLine = "Taw:  Hello World";  // use your own lines!
    var  chatstr = cLine.Split(new string[] { ": " }, 2, StringSplitOptions.None);
    AppendLineBold(yourrichTextBox, "\n" + chatstr[0], true);
    AppendLineBold(yourrichTextBox, chatstr[1], false);
    yourrichTextBox.ScrollToCaret();
}

void AppendLineBold(RichTextBox rtb, string text, bool bold)
{
    rtb.SelectionStart = richTextBox1.Text.Length;
    rtb.SelectionLength = 0;
    using (Font font = new Font(rtb.SelectionFont, 
                                bold ? FontStyle.Bold : FontStyle.Regular))
        rtb.SelectionFont = font;
    rtb.AppendText(text);
}
更新3:

看起来
ReadOnly
属性不允许使用
Cut
。因此,我们需要暂时允许改变


有趣的是:
SelectedText
也不能设置,但是
AppendText
可以很好地工作。

要保持文本格式,您还可以尝试以下操作(它稍微短一点,也应该可以做到这一点)


正确的方法不是
跳过
行或重新格式化周围的行,而是首先选择要删除的行,然后使用
剪切
删除它们。对不起,我不明白。我该怎么做?我找不到
string[]
Cut
方法。请参阅我的答案。剪切是RichTextBox操作其内容和格式所需的多种方法之一。
索引自动文本异常是因为
之后没有文本:“
。我在新答案中插入了一个复选框。在“:”之后不应出现文本,因为不可能发送空消息。我想我是在摆弄WordWrap属性。谢谢你,但不知怎么的,它还是不起作用。现在第一行(应该删除的那一行)变为粗体(用户名和消息),直到WordWrap插入换行符。新的生产线是完全正常的。此外,第一行不会被删除:(@St.Helen——确保正确调用该方法。然后新行必须像通常那样格式化。我只是在
if
部分中使用它,而不是调用函数。我使用0表示
fromLine
,1表示
fromLine+count
。应该也能工作吗?我没有更改
if
下面的任何内容,所以我不会更改为什么新行是完全规则的。现在有点难说你的代码是什么样子。我在你的文章中没有看到任何代码进行任何选择。这可能是问题所在!-没有它,你就不能正确格式化RTB!!附加文本将在它前面得到文本的格式,如果并且只有当文本格式正确!我如果格式化在换行符之前停止,它将不会继续。。也可以通过几个示例查看我的更新。@TaW我只想在每次执行lin时删除第一行