Search code examples
windows-runtimesystem.reactivewinrt-xamlwinrt-async

RX throttle on WinRT TemplatedControl


I have some problems with thread synchronization in my Templated control (trying to do a AutoComplete control)

Inside my control I have this code:

protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var searchTextBox = GetTemplateChild("SearchTextBox") as TextBox;
        if (searchTextBox != null)
        {
            var searchDelegate = SearchAsync;

            Observable.FromEventPattern(searchTextBox, "TextChanged")
                .Select(keyup => searchTextBox.Text)
                .Where(TextIsLongEnough)
                .Throttle(TimeSpan.FromMilliseconds(500))
                .Do(ShowProgressBar)
                .SelectMany(searchDelegate)
                .ObserveOn(Dispatcher)
                .Subscribe(async results => await RunOnDispatcher(() =>
                                                                      {
                                                                          IsInProgress = false;
                                                                          SearchResults.Clear();
                                                                          foreach (var result in results)
                                                                          {
                                                                              SearchResults.Add(result);
                                                                          }
                                                                      }));
        }
    }

And it is complaining that inside my ShowProgressBar method I'm trying to access code that was marshalled by another thread.

If I comment out the Throttle and the ObserveOn(Dispatcher) it works just fine, but it does not throttle my service calls as I want to.

If I only comment out the Throttle part, Nothing happens at all.


Solution

  • Asti's got the right idea, but a far better approach would be to provide the IScheduler argument to Throttle instead:

    // NB: Too lazy to look up real name 
    .Throttle(TimeSpan.FromMilliseconds(500), CoreDispatcherScheduler.Instance) 
    

    This will make operations below it happen on the UI thread (including your ShowProgressBar), up until the SelectMany.