-1

I am making a program that reads 1 file and writes it to another file, and the main thing is to make a ProgressBar there that will show progress, but when it starts, it swears that ProgressBar and the charCount variable that reads how many characters in a text file are in another stream. I used Dispatcher.Invoke(() => and the program worked but now it hangs until this thread finishes its job.

Thread thread = new Thread(
            () =>
            {
                Dispatcher.Invoke(() =>
                {
                    while (progBar.Value < charCount)
                    {
                        progBar.Value++;
                        Thread.Sleep(100);

                    }
                });
            });
thread.Start();

(progBar: ProgressBar name, charCount: stores the number of characters in a text file).

here is a piece of that code. It's strange that the same code without Dispatcher worked in Windows Forms and changed the value of the ProgressBar without hanging. Here it either freezes if you put Sleep(), or instantly changes the value of ProgressBar without Sleep().

I need that while the program is running, the second thread that I create has the ProgressBar value so that the bar fills up without braking the main program.

UPD: I have to use the Thread method.

Here is what the code should look like

Thread thread = new Thread(
            () =>
            {
                while (progBar.Value < charCount)
                {
                    progBar.Value++;
                    Thread.Sleep(100);
                }
            });
        thread.Start();
  • What .NET platform are you targeting? .NET 7? – Theodor Zoulias Feb 18 '23 at 12:27
  • 1
    Besides that you should not directly create a Thread, the straightforward solution here is to move Dispatcher.Invoke inside the loop: `while (...) { Dispatcher.Invoke(() => progBar.Value++); Thread.Sleep(100); }`. And never call Thread.Sleep in the UI thread, e.g. inside a Dispatcher action. – Clemens Feb 18 '23 at 12:31
  • And you would of course just use a timer, i.e. a DispatcherTimer in WPF. – Clemens Feb 18 '23 at 12:33
  • 1
    With binding it would just work.... Also there is many answersto o similar questions using Progress – Selvin Feb 18 '23 at 12:36

1 Answers1

0

Move the Dispatcher call into the loop body. Otherwise the loop - including the Thread.Sleep call - is executed in the UI thread, which will block all UI updates.

here is a sample code to demonstrate how to read from 1 file and write to another file with a progress presentation. you can change it based on your need

Thread thread = new Thread(() =>
{
    using (StreamReader reader = new StreamReader("input.txt"))
    using (StreamWriter writer = new StreamWriter("output.txt"))
    {
        int charCount = (int)reader.BaseStream.Length;
        int bytesRead = 0;
        char[] buffer = new char[4096];
        int read;

        while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
        {
            writer.Write(buffer, 0, read);
            bytesRead += read;

            if (updateCounter++ % 100 == 0)
            {
                int progress = (int)((double)bytesRead / charCount * 100);
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    progBar.Value = progress;
                }));
            }
        }
    }
});

thread.Start();
Clemens
  • 123,504
  • 12
  • 155
  • 268
Hamid Mohammadi
  • 286
  • 1
  • 10
  • This is not a matter of Invoke vs BeginInvoke, but just where the Dispatcher is called. Dispatcher.Invoke never blocks the UI thread. – Clemens Feb 18 '23 at 12:30
  • yes. you are right. we can add `if (updateCounter++ % 100 == 0)` before `Dispatcher` call to update progress bar less frequently to avoid blocking. i will update the code – Hamid Mohammadi Feb 18 '23 at 12:36