disasterkid
disasterkid

Reputation: 7278

Wait until file completely read and then display the result in a rich textbox

I know that you cannot have GUI controls to work in a separate thread. On my form load I would like to read from a text file and then display the contents in a rich text box. I do the reading in a separate thread but since eventually I would like this text to appear on my Rich Textbox, my window still freezes and my loading spinner does not animate.

private async void PreviewFileForm_Load(object sender, EventArgs e)
{
    string fileName = Path.GetFileName(this.filePath);
    lblFileName.Text = fileName;
    richtxtboxPreview.Visible = false;
    string fileContents = await ReadFileAsync(this.filePath);
    richtxtboxPreview.Text = fileContents;
    richtxtboxPreview.Visible = true;
    spinnerLoadFile.Visible = false;
}

async Task<string> ReadFileAsync(string filePath)
{
    string s = String.Empty;
    await Task.Run(() =>
    {           
        using (StreamReader sr = File.OpenText(filePath))
        {
            s = sr.ReadToEnd();
        }
    });
    return s;
}

What can I do so that my loading bar spins to indicate waiting for the file to be read and then the rich text box show the result?

Upvotes: 0

Views: 907

Answers (1)

Matthew Watson
Matthew Watson

Reputation: 109547

You can use async file I/O to do this. Here's a Microsoft sample.

So if you implement your async file reader like this (change the encoding to be the right kind for your text file; this code is copied verbatim from the Microsoft sample linked above):

private async Task<string> readFileAsync(string filePath)
{
    using (FileStream sourceStream = new FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize : 4096, useAsync : true))
    {
        StringBuilder sb = new StringBuilder();

        byte[] buffer = new byte[0x1000];
        int numRead;
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
        {
            // Use correct encoding here; maybe you need Encoding.UTF8
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);
            sb.Append(text);
        }

        return sb.ToString();
    }
}

You should just be able to call it as you already are.

However, I've sometimes had weird things happen when doing stuff from the Load event.

In some cases, I fixed such problems by putting the code into a separate method and using BeingInvoke() to call it from the Load method, e.g.:

private void PreviewFileForm_Load(object sender, EventArgs e)
{
    this.BeginInvoke(new Action(doIt));
}

private async void doIt()
{
    string fileName = Path.GetFileName(this.filePath);
    lblFileName.Text = fileName;
    richtxtboxPreview.Visible = false;
    string fileContents = await ReadFileAsync(this.filePath);
    richtxtboxPreview.Text = fileContents;
    richtxtboxPreview.Visible = true;
    spinnerLoadFile.Visible = false;
}

Upvotes: 1

Related Questions