The (previously) accepted answer, unfortunately, continues to go the wrong way that you hit in the first place. The problem here is that "I had to update the user interface from the wrong thread by performing an asynchronous operation on the workflow." The above solution: "have a worker thread, marshal, call back to the user interface thread." The best solution is not trying to get the user interface to work with the workflow in the first place.
Also there is no need to guess with ContinueWith ; in C # 5 and above, we have an asynchronous wait.
Suppose we really have work that we want to do in another thread. (This is suspicious: there is no reason why the high-latency operation here should go on a different thread, and not on the processor! But for the sake of argument, let's assume that we want to load HTML into another thread:
async private void button1_Click(object sender, EventArgs e) {
Note that I noted the async method. This does not make it work in another thread. This means that "this method will return to its caller - the message loop that sent the event - before the method runs. It will resume inside the method at some point in the future."
var doc = await Task.Factory.StartNew(() => new HtmlWeb().Load(url));
What do we have? We create an asynchronous task that loads some HTML and returns the task. Then we expect this task. Waiting for a task means "return immediately to my caller - the message loop that sent the click button - so that the user interface runs. When the task finishes, this method will resume here and get the value calculated by the task."
Now the rest of the program is completely normal:
HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//a"); foreach(HtmlNode node in nodes) { listView1.Items.Add(node.InnerText); } }
We are still in the user interface thread; we are in the button handler. The only work that was done in another thread was to get the HTML, and when it was available, we resumed work here.
Now there are several problems.
What happens if the button is pressed again while we wait for the HTML to load? We are trying to download it again! It would be nice to turn off the button before waiting and come back again after.
Also, as I said earlier, why are we creating a thread for a network operation? You want to send a letter to your aunt and get an answer; You donโt need to hire an employee to take the letter to the mailbox, mail it, and then sit at the mailbox, waiting for an answer. Most of the operation will be carried out by the post office; you donโt need to hire an employee to do nothing but to nurse mail. The same thing here. The vast majority of the work will be carried out by the network; why do you hire a thread to look after it? Just find the asynchronous HTML loading method that returns the job and waits for the task to complete. HttpClient.GetAsync immediately comes to mind, although there may be others.
Third problem: we created an object in the workflow. Who says it's safe to use it in a user interface thread? There are many "stream models" that an object can have; in the COM world, they are traditionally called "apartments" (you can talk to me only on the topic in which you created me), "rent" (you can talk to me on any topic, but you must make sure that none of the two attempts at the same time), "free" (everything goes, the object is safe) and several others. It is assumed that the object in question is safe to โrentโ or better โ reading will not occur in the user interface thread until writing is done in the workflow. But if the object is truly an โapartment,โ then you have an object that you cannot talk to on any thread except the work thread that you just threw away. This is a potential real mess.
The moral of the story here is, firstly, to keep everything in one thread as much as possible , and the second not to turn your program inside out to make the work asynchronous; just use await .