1

ログメッセージを表示するためのLogTextBoxクラスがあります。

public class LogTextBox : TextBox
{
    int maxMessageCount, messageCount;

    //number of characters for each message
    List<int> messageLengths;

    public LogTextBox(int maxMessageCount)
    {
        this.messageCount = 0;
        this.maxMessageCount = maxMessageCount;
        this.messageLengths = new List<int>();

        IsReadOnly = true;
        IsUndoEnabled = false;
    }

    public void Log(string message)
    {
        if (messageCount >= maxMessageCount)
        {
            Dispatcher.Invoke((Action)delegate()
            {
                //statement 1
                string text = Text.Remove(0, messageLengths[0]);

                //statement 2
                Text = text + message + '\n';

                //statement 3
                ScrollToEnd();
            });

            messageLengths.RemoveAt(0);
            messageLengths.Add(message.Length + 1);
        }
        else
        {
            Dispatcher.Invoke((Action)delegate()
            {
                AppendText(message + '\n');
                ScrollToEnd();
            });

            messageLengths.Add(message.Length + 1);
            messageCount++;
        }
    }
}

public class Test
{
    public LogTextBox logView;

    public Timer timer;

    [STAThread]
    public static void Main()
    {
        Application app = new Application();
        Test test = new Test();

        test.logView = new LogTextBox(200);

        test.timer = new Timer(200);
        test.timer.Elapsed += new ElapsedEventHandler(test.timer_Elapsed);
        test.timer.Start();

        app.Run(main);
    }

    int line = 0;
    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        logView.Log(GetMessage(line++));
    }

    private string GetMessage(int line)
    {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 1000; i++)
            builder.Append(line + " ");

        builder.Append('\n');

        return builder.ToString();
    }
}

ステートメント3は、上記の構成で10回実行すると平均200ミリ秒かかります。ステートメント2がコメント化されている場合、ステートメント3は10回の実行で平均0.1ミリ秒かかります。Logメソッドの他の部分は、どちらの場合も平均10ミリ秒かかります。ステートメント1とステートメント2の実行時間は短く、重要ではありません。測定には高解像度のストップウォッチを使用しています。

Textプロパティが更新されると、なぜScrollToEndにこれほど時間がかかるのですか?ScrollToEnd(ステートメント3)の実行時間は、LogTextBoxコンストラクターでmaxMessageCountが500に設定されている場合、500ミリ秒かかるため、Textプロパティのサイズに比例します。使用済みメモリを制限するために最初のメッセージを削除してテキストを更新する必要がありますが、他の方法は見つかりませんでした。最初のメッセージを削除する他の方法はありますか?

編集:

提案され、TextBoxではなくTextEditorから派生したAvalonEditを試しました。メソッド名が同じなので、コードを変更する必要はありませんでした。ScrollToEnd(ステートメント3)は、同じテスト構成で平均0.02ミリ秒かかり、Textプロパティのサイズに関係なく一定に保たれます。その結果、パフォーマンスの問題が解決され、AvalonEditを使用します。ジェイコブが最初にアバロンエディットを提案したので、私はジェイコブに賞金を与えました。

TextBoxBase.ScrolltoEndはUpdateLayout(Reflectorを使用して以下に表示)を呼び出します。これがパフォーマンスの低下の理由だと思いますが、AvalonEditのTextEditor.ScrollToEndはScrollViewer.ScrollToEndを呼び出すだけです。

public void ScrollToEnd()
{
    if (this.ScrollViewer != null)
    {
        base.UpdateLayout();
        this.ScrollViewer.ScrollToEnd();
    }
}  
4

4 に答える 4

0

読みやすさが主要なドキュメント消費シナリオである場合。次に、フロードキュメントを使用してみてください。

注:このFlowDocumentは、表示と読みやすさを最適化するように設計されています。リッチテキストボックスFlowDocumentオブジェクトを操作するリッチ編集コントロールを表します。

編集:

  1. アプリケーションで1万を超える検索結果を期待しない場合は、TextBlockコントロールまたは読み取り専用の複数行のTextBoxで十分です。TextBoxクラスにはAppendText()メソッドがあり、これは十分に高速である必要があります。最初のメッセージを削除する必要はありません。

  2. 別のテキストボックスコントロールの使用を検討することもできます。これは、SharpDevelop用のWpfテキストエディタを完全にゼロから作成したものです。これはAvalonEditと呼ばれ、codeprojectに関する優れた記事があります。http: //www.codeproject.com/KB/edit/AvalonEdit.aspx 彼は大きなコンテンツの最適化を行ったようです。

于 2013-03-15T04:12:03.030 に答える
0

ステートメント2をから変更してみましたか

       //statement 2
       Text = text + message + '\n';

AppendText(message);
AppendText('\n');

これは単なる推測ですが、記述されているステートメント2は毎回新しい文字列オブジェクトを割り当てるため、ガベージコレクターが古い文字列を解放するためにキックインしている可能性があります。AppendTextは、中間の割り当てを回避する方法で実装されていると思います。

于 2013-03-18T21:49:24.493 に答える
0

別のテキストボックスコントロールの使用を検討してみませんか?

テキストの強調表示をサポートするAvalonEditを試すことができます。これについては、 http://www.codeproject.com/KB/edit/AvalonEdit.aspxで読むことができます。

ネイティブのWPFリッチテキストコントロールよりも高速なようです。

于 2013-03-19T08:40:10.353 に答える
0

logbox.ScrollToVerticalOffset(double.MaxValue);よりも最大1/3速いことがわかりましたlogbox.ScrollToEnd();。おそらく、への内部呼び出しを回避するためUpdateLayout()です。

于 2017-10-26T17:27:52.590 に答える