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

标签 c# winforms visual-studio

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

编辑

我可以解决无法删除第一行的问题。 我必须将 ReadOnly 属性设置为 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();

因此,删除行有效,并且新行会按预期添加。终于!

已解决:)

最佳答案

切勿更改 RichtTextBox文本(如果它包含任何格式)。

更改Lines属性(通过Skip)只是更改Text的另一种方法。

相反,使用 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);

要将文本限制为 10 行,请使用:

DeleteLines(yourRTB, 0, yourRTB.Lines.Length - 10);

请注意,上面的函数应该对有效输入进行一些检查;我将它们排除在外,因为检查在某种程度上需要决定要做什么,如果 countfromLine 如果大于 Lines.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;  
  }

关于 NewLine 的一句话:请注意,我没有使用过 Environment.NewLine 常量,因为它并不是一个很好的选择。想法。如果您将多行文本添加到设计器中的 RichTextBox 中,然后查看它,您会发现它使用简单的 '\n' 换行符,没有回车,没有 NL-CR,只是 '\n' 。所以这似乎是 winforms RTB 中的通用方式,我建议使用它..

新函数依赖于所有具有相同长度换行符的行!

为了确保您可以使用此替换功能:

int RTBReplace(RichTextBox rtb, string oldText, string newText)
{
    int p = 0; int count = 0;
    do
    {
        p = richTextBox1.Text.IndexOf(oldText);
        if (p >= 0)
        {
            richTextBox1.SelectionStart = p;
            richTextBox1.SelectionLength = oldText.Length;
            richTextBox1.SelectedText = newText;
            count ++;
        }
    }
    while (p >= 0);
    return count;
}

这样调用它:

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 工作正常..

关于C# 删除行后在 RichTextBox 中丢失字体样式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36950939/

相关文章:

c# - 哪些 System.Drawing 类算作 GDI 对象?

visual-studio - 我应该使用什么开发工具在 F# 中编码?

visual-studio - 使用 WriteCodeFragment MSBuild 任务

c# - 尝试将 2 个文件添加到单独的列表中进行读取,我需要将它们合并到一个列表中

c# - 使用 C# 将数据发送到接受 JSON 数据的通用处理程序

c# - Crystal 报表 PrintToPrinter 没有安装打印机问题

sql-server - SSDT - 在架构创建时指定授权用户

c# - 无需安装 .NET 框架即可创建独立的 exe

c# - WinForms:子窗体关闭父窗体

c# - 将 Powerpoint 演示嵌入到 C# 应用程序中