C # - Uploading a large file to WPF RichTextBox?

I need to upload a text file of a 10 MB range into a WPF RichTextBox, but my current code will slow down the interface. I tried to make a background worker by downloading, but that also does not work too well.

Here is my download code. Is there any way to improve its performance? Thanks.

//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"; } 
+6
c # wpf richtextbox
source share
8 answers

Graphical controls are simply not designed to handle this kind of data, simply because they will become inoperative. Even if the control can handle a large line, what is visible in the control is so small compared to the whole text that the scroll bars become almost useless. To find a specific line in the text, you need to move the slider to the nearest position that it could indicate, then scroll the line at a time in minutes ...

Instead of sending your users to something useless, you should rethink how you display the data so that you can do it in a way that you really could use.

+3
source share

I am working on a very similar project.

The project involves loading a large text file (maximum size approximately: 120 MB, but we want to go higher), and then construct the outline of the text file in the tree. Clicking on a node in the tree will scroll the user to this part of the text file.

After talking with a lot of people, I think that the best solution is to create a kind of "sliding window" in which you load as much text as the user can see at a time in rtb.Text.

So let's say upload the whole file to the list, but just put 100 of these lines in rtb.Text. If the user scrolls up, remove the bottom line and add a line of text at the top. If they scroll down, delete the top line and add a line of text at the bottom. I get pretty good performance with this solution. (50 seconds to download a 120 MB file)

+2
source share

The WPF RichTextBox control uses the Flow Document to display the Rich Text, and then attaches the Flow Flow to the RTB control, while the Windows Form RichTextBox control displays the Rich Text directly. which makes WPF RTB super slow. if you agree to using WinForm RTB, just put it in your wpf application. 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 # code

 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(); } 
+2
source share

Why don't you add a string variable (or maybe even use a StringBuilder), then assign a value to the .Text property when you finish the parsing?

+1
source share

I drew attention to the use of RichTextboxes, because when you add more lines, it starts to slow down. If you can do this without adding "\ n", this will speed up for you. Remember that each '\ n' is a new block of paragraph objects for RichTextbox.

This is my method for uploading a 10 MB file. Download takes about 30 seconds. I am using the progress bar dialog so that my user knows that it will take time to load.

 // 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); } 
+1
source share

You can try, it worked for me.

 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(); } 
0
source share

Do you consider an attempt to make the application multithreaded?

How much text file do you need to see at once? You might want to take a look at lazy loading in .NET or in your case C #

-one
source share

I do not improve download performance, but I use it to load my richtextbox asynchronously. Hope this helps you.

XAML:

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

Assistant:

 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(); } } 
-one
source share

All Articles