Question

I have this event:

private void  TextBoxSearchText_TextChanged(object sender, TextChangedEventArgs e)
{
    searchText();
}

and I want to cancel this parallel method and start a new one when textbox text changes and also want my textbox be responsive to my new text typing, which is lock until results come to listbox.

List<TextList> oSelected;
private void searchText()
{
string strSearchText = TextBoxSearchText.Text;
    oSelected = new List<TextList>();            
    Parallel.ForEach(oTextList, item  =>
    {
        Match myMatch = Regex.Match(item.EnglishText.ToString(), "\\b" + strSearchText.ToString().ToLower() + @"\w*", RegexOptions.IgnoreCase);
        if (!myMatch.Success)
        {
            return;
        }

        oSelected.Add(new TextList
        {
            Id = item.Id,
            EnglishText = item.EnglishText
        });
    });

    ListBoxAllTexts.ItemsSource = oSelected;
}

Is it possible to use async and awiat to accomplish the job? Which one is better for searching a text in almost 1 million line of text? I read alot about async and await but I couldn't understand how to use it in my work. Thank you

Était-ce utile?

La solution

Since your work is CPU-bound, you should use parallel code to do the actual search. However, you can wrap the parallel work in an async/await mindset by using Task.Run:

private async void TextBoxSearchText_TextChanged(object sender, TextChangedEventArgs e)
{
  ListBoxAllTexts.ItemsSource = await Task.Run(() => searchText(TextBoxSearchText.Text));
}

This will keep your UI responsive.

To do cancellation, use a CancellationTokenSource. On a side note, you can't update a List<T> from a parallel loop like you're currently trying to do because List<T> is not threadsafe. In this scenario, I recommend you use PLINQ instead:

private CancellationTokenSource _cts;
private async void TextBoxSearchText_TextChanged(object sender, TextChangedEventArgs e)
{
  if (_cts != null)
    _cts.Cancel();
  _cts = new CancellationTokenSource();
  var strSearchText = TextBoxSearchText.Text;
  ListBoxAllTexts.ItemsSource = await Task.Run(
      () => searchText(strSearchText, _cts.Token));
}

private List<TextList> searchText(string strSearchText, CancellationToken token)
{
  try
  {
    return oTextList.AsParallel().WithCancellation(token)
        .Where(item => Regex.IsMatch(item.EnglishText.ToString(), "\\b" + strSearchText.ToLower() + @"\w*", RegexOptions.IgnoreCase))
        .Select(item => new TextList
        {
          Id = item.Id,
          EnglishText = item.EnglishText
        })
        .ToList();
  }
  catch (OperationCanceledException)
  {
    return null;
  }
}

Also, consider throttling the user input by only starting the search after a delay. Rx is the best way to do that.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top