coalmee
coalmee

Reputation: 1556

C# Observable delay until certain condition met

I'm currently implementing an autocomplete which triggers a search on a web service when a user enters a text.

textChange.Subscribe(this.TextChanged);

Additionally I have a property in my class indicating if a search is running IsRunning.

Now I want to buffer the user input while IsRunning==true and fire the TextChange method only if IsRunning==false with newly entered text.

Could you help me out?

Edit: Sample code to get the idea without using reactive:

    public class AutoComplete
    {
        private bool isRunning;
        private string textBuffer;


        public AutoComplete()
        {
            this.textChanged += this.TextChanged;
        }

        public void TextChanged(string text)
        {
            if (isRunning) textBuffer = text;
            else Search(text);
        }

        public void Search(string text)
        {
            isRunning = true;
            // DoSearch()
            isRunning = false;

            // TODO: Search finished, check if textBuffer was filled and reexecute search with the new termn
        }
    }

Upvotes: 0

Views: 1042

Answers (1)

reijerh
reijerh

Reputation: 815

Since you haven't tried much with Rx yourself I'm just going to give some pointers:

  1. Lose the isRunning bool, you want to try to keep as little state as possible when using Rx.
  2. Use Select() to transform the input search string to a Task that performs the search, have the Task return the results.
  3. Use Switch() to discard all search tasks that are still in progress except for the last search task. See also: http://www.introtorx.com/content/v1.0.10621.0/12_CombiningSequences.html#Switch
  4. You'll need to transform the search Task into an observable using Observable.FromAsync().
  5. Optionally, use Throttle() to limit the number of requests (so your server won't be overloaded with requests).

Edit: since you don't want multiple searches running at the same time, you'll need to block the stream while a search is running. You'll need to do something like:

searchTermStream    
.Select(l => Observable.FromAsync(asyncSearchMethod))
.Concat()
.Subscribe();

The Concat() operator makes sure a task is only started after the previous one has returned a result.

I predict this is going to feel laggy for the users though, because the searches will take longer than the user needs to enter a new character.

Upvotes: 3

Related Questions