FastColoredTextBox: How add large text – similar to StringBuilder but using styles – and without building undo history

huangapple go评论67阅读模式
英文:

FastColoredTextBox: How add large text - similar to StringBuilder but using styles - and without building undo history

问题

FastColoredTextBox (FCTB) does provide StringBuilder-like methods, for example there is

public virtual void AppendText(string text, Style style)

and similar methods. However, it treats each of these as user input: each action is added to the undo history.

I am building my text programmatically, it is data fields and text, along with all the formatting and styles, and it gets large. At the end I throw away that undo history (or set the control to read only). A lot is wasted in memory and computation time. It takes a few seconds before the control is usable.

So is there a way to build my text before passing it to the FCTB?

英文:

FastColoredTextBox (FCTB) does provide StringBuilder-like methods, for example there is

> public virtual void AppendText(string text, Style style)

and similar methods. However, it treats each of these as user input: each action is added to the undo history.

I am building my text programmatically, it is data fields and text, along with all the formatting and styles, and it gets large. At the end I throw away that undo history (or set the control to read only). A lot is wasted in memory and computation time. It takes a few seconds before the control is usable.

So is there a way to build my text before passing it to the FCTB?

答案1

得分: 0

创建一个派生自TextSource的类:

public class TextBuilder : TextSource
{
    public Line CurrentLine { get; private set; }

    public TextBuilder(FastColoredTextBox t) : base(t)
    {
        AppendLine();
    }

    public void Append(string text, StyleIndex style = StyleIndex.None)
    {
        for (int i = 0; i < text.Length; i++)
        {
            char c = text[i];
            if (c == '\r' && i < text.Length - 1 && text[i + 1] == '\n') continue;
            if (c == '\r' || c == '\n') { AppendLine(); continue; }
            CurrentLine.Add(new Char(c, style));
        }
    }

    public void AppendLine(string text, StyleIndex style = StyleIndex.None)
    {
        Append(text, style);
        AppendLine();
    }

    public void AppendLine()
    {
        CurrentLine = CreateLine();
        lines.Add(CurrentLine);
    }

    public override void Initialized()
    {
        // Solution similar to CustomTextSourceSample.cs (not more than necessary)
        // (an alternative is OnTextChanged(0, lines.Count - 1) which invokes TextChanged but there may be side effects)

        if (CurrentTB.WordWrap)
        {
            OnRecalcWordWrap(new TextChangedEventArgs(0, lines.Count - 1));
        }

        CurrentTB.Invalidate();
    }
}

TextSource类中添加这个虚方法:

/// <summary>
/// 当CurrentTB初始化此文本源时调用。
/// </summary>
public virtual void Initialized()
{
}

FCTB类的InitTextSource方法中添加这行:

while (LineInfos.Count < ts.Count)
    LineInfos.Add(new LineInfo(-1));

ts.Initialized(); // 添加这行

为了方便,更改Char构造函数:

public Char(char c, StyleIndex s = StyleIndex.None)
{
    this.c = c;
    style = s;
}

使用方法如下:

var b = new TextBuilder(fctb);
b.Styles[0] = new MarkerStyle(Brushes.LightBlue);
b.Append("text", StyleIndex.Style0);
fctb.TextSource = b;

如果你不想重新编译FCTB,你可以创建TextBuilder类,去掉虚方法等,并在分配TextSource后调用b.OnTextChanged(0, b.Count - 1)

英文:

Create a TextSource-derived class:

public class TextBuilder : TextSource
{
    public Line CurrentLine { get; private set; }

    public TextBuilder(FastColoredTextBox t) : base(t)
    {
        AppendLine();
    }

    public void Append(string text, StyleIndex style = StyleIndex.None)
    {
        for (int i = 0; i < text.Length; i++)
        {
            char c = text[i];
            if (c == '\r' && i < text.Length - 1 && text[i + 1] == '\n') continue;
            if (c == '\r' || c == '\n') { AppendLine(); continue; }
            CurrentLine.Add(new Char(c, style));
        }
    }

    public void AppendLine(string text, StyleIndex style = StyleIndex.None)
    {
        Append(text, style);
        AppendLine();
    }

    public void AppendLine()
    {
        CurrentLine = CreateLine();
        lines.Add(CurrentLine);
    }

    public override void Initialized()
    {
        // Solution similar to CustomTextSourceSample.cs (not more than necessary)
        // (an alternative is OnTextChanged(0, lines.Count - 1) which invokes TextChanged but there may be side effects)

        if (CurrentTB.WordWrap)
        {
            OnRecalcWordWrap(new TextChangedEventArgs(0, lines.Count - 1));
        }

        CurrentTB.Invalidate();
    }
}

Add this virtual method to the TextSource class:

/// <summary>
/// Called when CurrentTB has initialized this text source.
/// </summary>
public virtual void Initialized()
{
}

In the FCTB class, add this line to the InitTextSource method:

while (LineInfos.Count < ts.Count)
    LineInfos.Add(new LineInfo(-1));

ts.Initialized(); // Add this line

Change the Char constructor for convenience:

public Char(char c, StyleIndex s = StyleIndex.None)
{
    this.c = c;
    style = s;
}

Use as follows:

var b = new TextBuilder(fctb);
b.Styles[0] = new MarkerStyle(Brushes.LightBlue);
b.Append("text", StyleIndex.Style0);
fctb.TextSource = b;

If you want to do it without recompiling FCTB you can just create the TextBuilder class minus virtual method etc. and call b.OnTextChanged(0, b.Count - 1) after assigning TextSource.

huangapple
  • 本文由 发表于 2023年3月8日 16:19:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75670697.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定