0

I'm trying to write a function that will dynamically create tab pages, populate the tabs, and then return data regarding what it has done. There are events that will tell me when each tab is done, so I'll be able to tell when they're all loaded.

All the work is UI-related, and my understanding is that UI stuff has to happen in the main thread, so it sounds like I can't just create a thread to do this and then wait on it in my function. Am I misunderstanding the issue with UI stuff having to be on the main thread? How can I have my function wait without blocking the work that has to happen in the UI?

EDIT: To clarify, the tab pages have webbrowser controls which will load various web pages, so those take some amount of time and I get a DocumentCompleted event for each when it's loaded. The idea is this: The caller hands me a list of urls. I pop up a form and create a tab page containing a web browser control for each url, and load one url in each tab. These will complete at different times, each firing a DocumentComplete event handler when a page has loaded. When they've all loaded, I want to return a list of data to the original caller.

alanc10n
  • 4,897
  • 7
  • 36
  • 41
  • If you want to work from a background thread and modify UI controls without as if you were in the main thread, take a look at my answer. – Oscar Mederos May 08 '11 at 00:12

2 Answers2

1

...and my understanding is that UI stuff has to happen in the main thread...

No, that's not necessarily true. If you want to modify, let's say, a label from a background thread, you can do:

MethodInvoker m = () => { label1.Text = "Another text"; };
if (InvokeRequired) {
    BeginInvoke(m);
}
else {
    m.Invoke();
}

instead of:

label1.Text = "Another text";

If you are carefully with that, you won't have any cross-thread problems.

Edit:
Take a look at the answer I provided in the question Client Coding error for chatting application if you want to refactor a little bit that code.

Edit 2:
According to your edit, this is how I would do that:

  1. Receive the urls from the user
  2. Start each browser and a variable that will hold how many tabs you opened.
  3. Start a progressbar or something that tells the user the application is working...
  4. Everytime you receive a DocumentComplete event, you decrease the variable.
    If the value of the variable is 0, then all pages were loaded.
  5. Stop progress bar
  6. Return the data you want to the user.

Now.. when will you need to use the Invoke? Everytime you want to access to some UI control from the background thread. In that case, when you're stopping the progress bar...

Community
  • 1
  • 1
Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124
  • But how do I wait until the UI stuff is all done before I return to the caller? The whole idea is that someone gives me the list of URLs and I build this form and return info once everything has loaded. Does the caller need to create a thread and call my function there, so I can block in my code without blocking the UI thread? – alanc10n May 08 '11 at 00:18
  • @idontwanttortfm I suggest you starting a progress bar or something that tells the user that the application is working. Take a look at the answer I provided here: http://stackoverflow.com/questions/5919964/how-best-execute-query-in-background-to-not-freeze-application-net/5920027#5920027 I think both questions are similar. – Oscar Mederos May 08 '11 at 00:21
  • The caller isn't the user, though. I'm worried about collecting this information and returning it to the caller. I can't collect and return it until the browser controls have finished loading their web content. – alanc10n May 08 '11 at 00:32
  • Thanks for spending the time to help me with this. The part where I'm still confused is between 4 and 6, namely how I'm waiting until I get all the DocumentComplete events before returning to the caller. Does he have to create a thread and call my function in it so I can call sleep in a loop while I'm waiting for all the events to fire? If not, how am I supposed to avoid returning before the events fire? – alanc10n May 08 '11 at 01:44
0

I am not sure I've got you right. Anyway, take a look at this:

How to update the GUI from another thread in C#?

Community
  • 1
  • 1
Akram Shahda
  • 14,655
  • 4
  • 45
  • 65
  • The idea is this: The caller hands me a list of urls. I pop up a form and create a tab page containing a web browser control for each url, and load one url in each tab. These will complete at different times, each firing a DocumentComplete event handler when a page has loaded. When they've all loaded, I want to return a list of data to the original caller. – alanc10n May 08 '11 at 00:09