If you wish to reduce the number of starts and cancels - I would put a delay into your execution. Another approach would be to use polling but that's more overhead and more complex; and violates the good policy of "Tell, don't ask".
I think something like this may do the job of only grabbing the search string after a delay, so they can type a few characters before it grabs it and begins the execution. If execution is already occurring you still want to cancel and kick off another delay though. This way if they start and finish typing before the delay is over, it won't be cancelled and it'll execute the query right then.
private CancellationTokenSource cts = null; private Task<List<string>> searchTask; private Task delayTask; private ConcurrentQueue<string> searchStringOrganizer = newstring ConcurrentQueue<string>();searchString; private async void textbox_TextChanged(object sender, TextChangedEventArgs e) { string removedToNotBeUsed; searchString = searchStringOrganizer.Enqueue(txtbox.Text); searchStringOrganizer.TryDequeue(out removedToNotBeUsed);Text; if (delayTask != null && !delayTask.IsCompleted) return; //there is already running task if (searchTask != null && !searchTask.IsCompleted) { //cancel the running and start a new one cts.Cancel(); cts = new CancellationTokenSource(); } ExecuteQueryAfterDelay(); } private void ExecuteQueryAfterDelay() { delayTask = Task.Delay(2000).ContinueWith(t => { string stringToSearchFor = ""; searchStringOrganizer.TryDequeue(out stringToSearchFor); searchTask=SearchWeb(stringToSearchForsearchString, cts.Token); searchTask.ContinueWith(t => { //show results }); }); }