7

~ 10MB の範囲のテキスト ファイルを WPF RichTextBox にロードする必要がありますが、現在のコードでは UI がフリーズしています。バックグラウンド ワーカーに読み込みを行わせようとしましたが、それもうまく機能していないようです。

これが私の読み込みコードです。そのパフォーマンスを改善する方法はありますか?ありがとう。

    //works well for small files only
    private void LoadTextDocument(string fileName, RichTextBox rtb)
    {
        System.IO.StreamReader objReader = new StreamReader(fileName);

        if (File.Exists(fileName))
        {
                rtb.AppendText(objReader.ReadToEnd());
        }
        else rtb.AppendText("ERROR: File not found!");
        objReader.Close();
    }






    //background worker version. doesnt work well
    private void LoadBigTextDocument(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        System.IO.StreamReader objReader = new StreamReader(   ((string[])e.Argument)[0]  );
        StringBuilder sB = new StringBuilder("For performance reasons, only the first 1500 lines are displayed. If you need to view the entire output, use an external program.\n", 5000);

            int bigcount = 0;
            int count = 1;
            while (objReader.Peek() > -1)
            {
                sB.Append(objReader.ReadLine()).Append("\n");
                count++;
                if (count % 100 == 0 && bigcount < 15)
                {
                    worker.ReportProgress(bigcount, sB.ToString());

                    bigcount++;
                    sB.Length = 0;
                }
            }
        objReader.Close();
        e.Result = "Done";
    }
4

8 に答える 8

3

WPF RichTextBox コントロールはフロー ドキュメントを使用してリッチ テキストを表示し、フロー ドキュメントを RTB コントロールにアタッチしますが、Windows フォームの RichTextBox コントロールはリッチ テキストを直接表示します。それが WPF RTB を非常に遅くしている理由です。WinForm RTB を使用しても問題ない場合は、wpf アプリでホストするだけです。xaml:

<Window x:Class="WpfHostWfRTB.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
    <Grid>
        <WindowsFormsHost Background="DarkGray" Grid.row="0" Grid.column="0">
            <wf:RichTextBox x:Name="rtb"/>
        </WindowsFormsHost>
    </Grid>
</Grid>
</Window>

C# コード

private void LoadTextDocument(string fileName, RichTextBox rtb)
{
    System.IO.StreamReader objReader = new StreamReader(fileName);
        if (File.Exists(fileName))
        {
            rtb.AppendText(objReader.ReadToEnd());
        }
        else rtb.AppendText("ERROR: File not found!");
        objReader.Close();
}
于 2014-05-28T06:32:54.983 に答える
2

RichTextboxes を使用すると、「行」を追加すると速度が低下することに気付きました。「\n」を追加せずに実行できる場合は、速度が向上します。各 '\n' は、RichTextbox の新しい段落オブジェクト ブロックであることを忘れないでください。

これは、10 MB のファイルをロードするための私の方法です。読み込みには約 30 秒かかります。プログレス バー ダイアログ ボックスを使用して、読み込みに時間がかかることをユーザーに知らせています。

// Get Stream of the file
fileReader = new StreamReader(File.Open(this.FileName, FileMode.Open));

FileInfo fileInfo = new FileInfo(this.FileName);

long bytesRead = 0;

// Change the 75 for performance.  Find a number that suits your application best
int bufferLength = 1024 * 75;

while (!fileReader.EndOfStream)
{
    double completePercent = ((double)bytesRead / (double)fileInfo.Length);

    // I am using my own Progress Bar Dialog I left in here to show an example
    this.ProgressBar.UpdateProgressBar(completePercent);

    int readLength = bufferLength;

    if ((fileInfo.Length - bytesRead) < readLength)
    {
        // There is less in the file than the lenght I am going to read so change it to the 
        // smaller value
        readLength = (int)(fileInfo.Length - bytesRead);
    }

    char[] buffer = new char[readLength];

    // GEt the next chunk of the file
    bytesRead += (long)(fileReader.Read(buffer, 0, readLength));

    // This will help the file load much faster
    string currentLine = new string(buffer).Replace("\n", string.Empty);

    // Load in background
    this.Dispatcher.BeginInvoke(new Action(() =>
        {
            TextRange range = new TextRange(textBox.Document.ContentEnd, textBox.Document.ContentEnd);
            range.Text = currentLine;

        }), DispatcherPriority.Normal);
}
于 2009-06-12T15:01:49.223 に答える
2

私は非常によく似たプロジェクトに取り組んでいます。

このプロジェクトでは、大きなテキスト ファイル (最大サイズは約 120 MB ですが、もっと大きくしたい) をロードし、テキスト ファイルのアウトラインをツリーに作成する必要があります。ツリー内のノードをクリックすると、ユーザーはテキスト ファイルのその部分にスクロールします。

多くの人と話し合った結果、最善の解決策は、ユーザーが一度に見ることができるテキストだけを rtb.Text にロードする一種の「スライディング ウィンドウ」ビューアーを作成することだと思います。

つまり、ファイル全体をリストにロードし、そのうちの 100 行だけを rtb.Text に入れるとします。ユーザーが上にスクロールした場合は、一番下の行を削除し、一番上にテキスト行を追加します。下にスクロールする場合は、一番上の行を削除し、一番下にテキスト行を追加します。このソリューションでかなり良いパフォーマンスが得られます。(120MBのファイルをロードするのに50秒)

于 2009-06-26T21:38:02.577 に答える
0

解析が完了したら、文字列変数に追加して (または StringBuilder を使用して)、値を .Text プロパティに割り当ててみませんか?

于 2009-05-07T21:17:46.933 に答える
0

これを試すことができます。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // Create new StreamReader
    StreamReader sr = new StreamReader(openFileDialog1.FileName, Encoding.Default);
    // Get all text from the file
    string str = sr.ReadToEnd();
    // Close the StreamReader
    sr.Close();

    // Show the text in the rich textbox rtbMain
    backgroundWorker1.ReportProgress(1, str);
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // richTextBox1.Text = e.ProgressPercentage.ToString() + " " + e.UserState.ToString();
    richTextBox1.Text = e.UserState.ToString();
}
于 2011-06-29T01:37:50.233 に答える
-1

読み込みのパフォーマンスを向上させるわけではありませんが、これを使用してリッチテキスト ボックスを非同期に読み込みます。お役に立てば幸いです。

XAML :

<RichTextBox Helpers:RichTextBoxHelper.BindableSource="{Binding PathFileName}" />

ヘルパー:

public class RichTextBoxHelper
{
private static readonly ILog m_Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

public static readonly DependencyProperty BindableSourceProperty =
    DependencyProperty.RegisterAttached("BindableSource", typeof(string), typeof(RichTextBoxHelper), new UIPropertyMetadata(null, BindableSourcePropertyChanged));

public static string GetBindableSource(DependencyObject obj)
{
  return (string)obj.GetValue(BindableSourceProperty);
}

public static void SetBindableSource(DependencyObject obj, string value)
{
  obj.SetValue(BindableSourceProperty, value);
}

public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
  var thread = new Thread(
    () =>
    {
      try
      {
        var rtfBox = o as RichTextBox;
        var filename = e.NewValue as string;
        if (rtfBox != null && !string.IsNullOrEmpty(filename))
        {
          System.Windows.Application.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Background,
            (Action)delegate()
            {
              rtfBox.Selection.Load(new FileStream(filename, FileMode.Open), DataFormats.Rtf);
            });
        }
      }
      catch (Exception exception)
      {
        m_Logger.Error("RichTextBoxHelper ERROR : " + exception.Message, exception);
      }
    });
  thread.Start();
}
}
于 2013-10-24T10:13:46.913 に答える