0

I have the following code:

StatusLabel.Content = "Copying files...";

AutoCopy();

StatusLabel.Content = "Finished";

The above code is a button click and when I click the button, I expect to see a label with "Copying files...", then it will copying files via an AutoCopy method and then the label with "Finished"

I do not see "Copying files". All I see is the screen freeze up and then unfreezed with "Finished".

How can I get "Copying files to show..." and only after AutoCopy() is finished, do I want to show "Finished";

Xaisoft
  • 45,655
  • 87
  • 279
  • 432
  • 2
    `AutoCopy` is obviously occupying the UI thread meaning the `Message Loop` cannot be processed. http://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows – User 12345678 Apr 22 '13 at 17:47
  • 2
    Another day, another confused threading question. UI thread is locked by your `AutoCopy()` call, so UI is not updated. Run AutoCopy on a separate thread either as an async `Task` or `BackgroundWorker` – Sten Petrov Apr 22 '13 at 17:48
  • 2
    Number one [UI is not Data](http://stackoverflow.com/questions/14381402/wpf-programming-methodology/14382137#14382137) so you shouldn't be manipulating UI elements' properties in code. Number two you need to run your stuff asynchronously in order to leave the UI thread free to update the UI. – Federico Berasategui Apr 22 '13 at 17:49
  • if your using .net45 prefer to make as @StenPetrov mentioned your AutoCopy() function return a Task (if required and call await on the function) or just make it async if void return. Keeps your code sooo much cleaner – Viv Apr 22 '13 at 18:12
  • @ByteBlast - OK you gave me an idea. If I remove anything occupying the UI from AutoCopy(), it should work? Right? – Xaisoft Apr 22 '13 at 18:25
  • @StenPetrov - Sorry for the question, I was actually trying BackgroundWorker, but it was not updating, so I am assuming the problem now is AutoCopy is using UI elements. – Xaisoft Apr 22 '13 at 18:26

1 Answers1

2

As everyone said, your UI (main) thread is blocked during file copy operation.

You need to spin off a worker thread that does everything in the background.

Caution: Multithreading only adds complexity.

{
    ...
    System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();
    bw.DoWork += new DoWorkEventHandler(DoWork);
    bw.RunWorkerCompleted  += new RunWorkerCompletedEventHandler(RunWorkerCompleted);

    StatusLabel.Content = "Copying files...";

    bw.RunWorkerAsync();
    ...
}

private void DoWork(object sender, DoWorkEventArgs e)
{   
    AutoCopy();
}

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{   
    StatusLabel.Content = "Finished";
}
Abhinav
  • 2,085
  • 1
  • 18
  • 31
  • Several things I don't like in this implementation: extra methods DoWork and RunWorkerCompleted instead of `bw.DoWork+=(s,e)=>AutoCopy();` and similar for completed event. Using `BackgroundWorker` instead of `async/await` adds code bulk that's not needed. Otherwise I'd upvote – Sten Petrov Apr 22 '13 at 18:17
  • @StenPetrov `bw.DoWork+=(s,e)=>AutoCopy();` creates an extra method exactly like the code in this answer. I do agree `async`/`await` is probably simpler, but whether that's an option depends on the VS and .NET version. –  Apr 22 '13 at 18:19
  • @hvd sure, the lambda is a method too, but without the bloated source code. It also has benefit of keeping your logic together, chances are with several threaded calls like this over several maintenance cycles your methods will be out of order and hard to read – Sten Petrov Apr 22 '13 at 18:20
  • @StenPetrov Fair point, although the explicit method has the benefit of being reusable if other code should perform the copy too. I suppose it just depends on the situation. –  Apr 22 '13 at 18:25
  • Do I need 4.5 to use async/await? I have 4.0 – Xaisoft Apr 22 '13 at 18:26
  • 4.0 has async/await. I was planning to use async/await for solution, but I find backgroundworker more *informational*. – Abhinav Apr 22 '13 at 18:29
  • @Xaisoft if you're just taking the plunge in threading start with async/await - it's a bit more confusing to begin with but once you understand how it works it saves a lot of code, plus there are a lot of framework methods that support it so you'll benefit more over time. BackgroundWorker is simpler to understand but if you start there you'll have harder time grasping async/await – Sten Petrov Apr 22 '13 at 18:36
  • @Xaisoft `async`/`await` doesn't require .NET 4.5, but does require a C# 5 compiler on your development system (which effectively means you need either VS2012, or install .NET 4.5 and compile with `csc.exe`, even if your solution is targeted for 4.0) –  Apr 22 '13 at 18:39
  • I ended up going with BackgroundWorker. But I had to take care of 2 parts, one was removing all the UI stuff from AutoCopy(). After I did this, the BackGroundWorker ran fine and the UI updated fine. Thanks. – Xaisoft Apr 22 '13 at 18:40
  • @Xaisoft to add what Sten said, async/await is a little more complicated in 4.0 than in 4.5 – Abhinav Apr 22 '13 at 18:40