开发者

AutoComplete TextBox with only a single search BackgroundWorker - code sample?

This has been asked before here, but the answer there was simply "use BackgroundWorker", and I'm asking if there is a complete code开发者_如何学编程 sample available.

I'd like to create a standard AutocompleteTextBox that works with a timer, such that there is only one BackgroundWorker working on searching - if the user entered a few more keystrokes, but the old search is still running - that search shall be canceled gracefuly (via CancelAsync), and as soon as its canceled the new search will begin.

This is not so trivial to implement - are there any code samples of this?


I doubt you'll find a code sample that helps you with the specific issues you're talking about here. Here's how I'd do this. None of this code is tested, so beware of stupid bugs.

First, subclass TextBoxBase and add two basic methods to implement the search logic, with the following signatures:

private IEnumerable<string> PerformSearch(string text)
private DisplayResults(IEnumerable<string> results)

Add a private BackgroundWorker field named Worker to the class and set its DoWork and RunWorkerCompleted events to event handlers named Worker_DoWork and Worker.RunWorkerCompleted.

Override OnTextChanged:

public override void OnTextChanged(TextChangedEventArgs e)
{
   base.OnTextChanged(e);
   // if we're already cancelling a search, there's nothing more to do until
   // the cancellation is complete.
   if (Worker.CancellationPending)
   {
      return;
   }
   // if there's a search in progress, cancel it.
   if (Worker.IsBusy)
   {
      Worker.CancelAsync();
      return;
   }
   // there's no search in progress, so begin one using the current value
   // of the Text property.
   Worker.RunWorkerAsync(Text);
}

The Worker_DoWork event handler is pretty simple:

private void Worker_DoWork(object sender,
   RunWorkerCompletedEventArgs e)
{
   e.Result = PerformSearch((string) e.Argument);
}

The Worker_RunWorkerCompleted event handler looks something like this:

private void Worker_RunWorkerCompleted(object sender, 
   RunWorkerCompletedEventArgs e)
{
   // always check e.Error first, in case PerformSearch threw an exception.
   if (e.Error != null)
   {
      // in your version, you want to do real exception handling, not this.
      throw e.Error.InnerException;  
   }
   // if the worker was cancelled, it's because the user typed some more text, and
   // we want to launch a new search using what's currently in the Text property.
   if (e.Cancelled)
   {
      Worker.RunWorkerAsync(Text);
      return;
   }
   // if the worker wasn't cancelled, e.Result contains the results of the search.
   DisplayResults((IEnumerable<string> e.Result);
}

Note that DisplayResults should test any assumption it makes about the state of the text box. The text box may have been visible or enabled when the user launched the search and not be visible or enabled now, for instance. What happens if you use this text box in a modal dialog and the user cancels the dialog while the search is running?

Note also that if you have multiple instances of this control in your application, each one will have a different BackgroundWorker, so it's important that the PerformSearch method be thread-safe. If it's not, it will have to implement locking, so that if you launch a search in one text box it blocks and waits if another text box is currently using the shared resource.


I suggest using the AutoComplete feature in System.Windows.Forms.TextBox. You can customize it and build your completion stuff around this.

NOTE: AutoComplete feature is only available from .NET 2.0

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜