With .Net 4 enhancements for concurrent programming , such as TPL and undo , as Mark Byers mentioned. "Never break the thread! If you donโt know exactly what you are doing ... Not even that." the rule, fortunately, was relaxed.
Another tool that allows for a more โcompositeโ approach is Reactive Extensions for.NET (Rx) . On the project home page ..
Rx is a library for compiling asynchronous and event-based programs using observable collections.
Recently, they released a practical laboratory ....
Disabling Asynchronous Blues with Reactive Extensions for .NET
... includes a solution that, with an odd coincidence of time, addresses your example ... "Suppose you want to show the user the most relevant information for what they typed at any time" ... and the need to cancel / interrupt / stop task in progress.
Briefly from the Laboratory ...
In our current sample, weve building a simple dictionary that offers expression. When the user enters the search term, the application will be triggered by a call to the web service to get the sentence words back. Since we do not want to block the user interface, it is good to keep in touch with the dictionary asynchronously as well.
After an excellent step-by-step result, the resulting solution ...
var txt = new TextBox(); var lst = new ListBox { Top = txt.Height + 10 }; var frm = new Form { Controls = { txt, lst } }; // Turn the user input into a tamed sequence of strings. var textChanged = from evt in Observable .FromEvent<EventArgs>(txt, "TextChanged") select ((TextBox)evt.Sender).Text; var input = textChanged .Throttle(TimeSpan.FromSeconds(1)) .DistinctUntilChanged(); // Bridge with the web service MatchInDict method. var svc = new DictServiceSoapClient("DictServiceSoap"); var matchInDict = Observable .FromAsyncPattern<string, string, string, DictionaryWord[]> (svc.BeginMatchInDict, svc.EndMatchInDict); Func<string, IObservable<DictionaryWord[]>> matchInWordNetByPrefix = term => matchInDict("wn", term, "prefix"); // The grand composition connecting the user input with the web service. var res = from term in input from word in matchInWordNetByPrefix(term).TakeUntil(input) select word; // Synchronize with the UI thread and populate the ListBox or signal an error. using (res.ObserveOn(lst).Subscribe( words => { lst.Items.Clear(); lst.Items.AddRange((from word in words select word.Word).ToArray()); }, ex => { MessageBox.Show("An error occurred: " + ex.Message, frm.Text, MessageBoxButtons.OK, MessageBoxIcon.Error); })) { Application.Run(frm); } // Proper disposal happens upon exiting the application.
Enjoy.