2

I need to write a VB.Net 2008 applet to go through all the fixed-drives looking for some files. If I put the code in ButtonClick(), the UI freezes until the code is done:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'TODO Find way to avoid freezing UI while scanning fixed drives Dim drive As DriveInfo Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of String) Dim filepath As String For Each drive In DriveInfo.GetDrives() If drive.DriveType = DriveType.Fixed Then filelist = My.Computer.FileSystem.GetFiles(drive.ToString, FileIO.SearchOption.SearchAllSubDirectories, "MyFiles.*") For Each filepath In filelist 'Do stuff Next filepath End If Next drive End Sub 

Google returned information on a BackGroundWorker control: Is this the right/way to solve this issue? If not, what solution would you recommend, possibly with a really simple example?

FWIW, I read that Application.DoEvents() is a left-over from VBClassic and should be avoided.

Thank you.

1

4 Answers 4

5

The BackgroundWorker is a good way to solve your problem. Actually the documentation states this:

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks everyone for the feedback. I'll try the BackgroundWorker control, and disable the button before launching the background thread.
2

Put the process into a separate thread.... ...using the BackgroundWorker component.

Disable UI components that should not be usable while the process workd.

Finished - the UI will still be responsive.

1 Comment

Nice suggestion about disabling UI components that could interfere with the background task.
2

The key is to seperate the UI code from the actual functionality code. The time-consuming functionality should run on a seperate thread. To achieve this, you can either:

  1. Create and start a Thread object by yourself
  2. Create a Delegate and use asynchronous invokation (using BeginInvoke).
  3. Create and start a BackgroundWorker.

As you mentioned, you should avoid Application.DoEvents(). A proper breakdown of the application's functionality will allow you to create an application which is designed to be responsive, rather than creating a non-responsive application with DoEvents "fixes" (which is costly, considered bad practice, and implies a bad design).

Since your method doesn't return a value and doesn't update the UI, the fastest solution might be creating a Delegate and using "fire and forget" asynchronous invokation:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Call New Action(AddressOf DrivesIteration).BeginInvoke(Nothing, Nothing) End Sub Private Sub DrivesIteration() Dim drive As DriveInfo Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of String) Dim filepath As String For Each drive In DriveInfo.GetDrives() If drive.DriveType = DriveType.Fixed Then filelist = My.Computer.FileSystem.GetFiles(drive.ToString, FileIO.SearchOption.SearchAllSubDirectories, "MyFiles.*") For Each filepath In filelist DoStuff(...) Next End If Next End Sub 

BTW, For..Next blocks no longer have to end with "Next (something)", it is obsolete - VB now infers the (something) by itself, so there is no need to state it explicitly.

1 Comment

Thanks for the answer. I prefer to add the variable in Next for easier reading.
0

A. put up a PROGRESS BAR... update it and .REFRESH it ... If all you want is to show that your not dead.

B. DoEvents is evil sounds A LOT like "NEVER USE A GOTO..." pleeeeze pleeeze pleeeze there are times and circumstances where any language's syntax can be harmful AND helpful. Why jump through a million hoops just to essentially do "A" above?

<soapbox>

If you know that something takes a LONG TIME and you also know that no other operations can take place WHILE YOUR WAITING (i.e. it is essentially a serial process) than if you do ANYTHING like that and push it into "the background" then you'll be sprinkling "ITS_OK_TO_CONTINUE" booleans all through the rest of your code just waiting for the file process to end anyway.... whats the point of that? All you've done is complicate your code for the sake of... hmm... "good programming?" Not in my book.

Who cares if DoEvents is "left over" from the ICE AGE. Its EXACTLY the right thing in MANY circumstances. For example: The framework gives you ProgressBar.Refresh but you'll see that its not exactly "working" unless you post-pend a few DoEvents after it.

</soapbox>

C. A background task is just that -- background; and you generally use it to operate on NON-SERIAL tasks or at least asynchronous tasks that MAY or MAY NOT update the foreground at some point. But I'd argue that anytime a so-called background task HALTS the foreground then it is (almost) by definition --- a FOREGROUND task; regardless of HOW LONG it takes.

10 Comments

If you're having drawing problems, invalidate() and update() to repaint immediately. DoEvents is an ugly hack that causes strange problems to appear.
I think most of you have inferred way too much ... his problem is SIMPLE. DISABLING controls, creating delegates, using backgrounders; talk about overkill for what the OP indicated his problem was. And calling DoEvents a hack is actually kinda funny considering its history.
Tell me, what exactly do you think DoEvents does?
Forces VB main thread to "be nice" and allow other messaging threads to grab a few CPU cycles. In the case you're suggesting, its no better or worse than adding .invalidate and .repaint. They are doing the same thing. EXCEPT that there may be other threads that need attention other than the GUI thread(s.) Let me ask you what your experience has been which makes you say that it CAUSES strange problems?
Quite a few, actually. First one that comes to mind is a C# 2.0 app where pressing enter down in a textbox would validate a field then spawn a new form. On larger forms that took a long time to load, though, we'd have a crash, a ding, or something else unexpected happen depending on what was going on when DoEvents() made KeyUp run before KeyDown finished.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.