2012-09-22 55 views
0

我有我的模板化控件的一些问题与线程同步(试图做一个自动完成控制)RX油门

在我的控制我有这样的代码:

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); 
                      } 
                     })); 
     } 
    } 

而且它抱怨在我的ShowProgressBar方法中,我试图访问由另一个线程编组的代码。

如果我将Throttle和ObserveOn(调度程序)注释掉,它工作得很好,但它并没有像我想的那样限制我的服务调用。

如果我只注释出Throttle部分,则根本没有任何反应。

+0

我使用的是RX 2.0 beta – David

+0

这不是一个答案,而是一个快速评论 - 我不认为你需要在代码中使用'async' /'await'。 Rx有效地等待着你。尝试一下,并让我知道如果它仍然正常工作。 – Enigmativity

+0

真正的Enigmativity - 代码无需异步/等待。 – David

回答

1

阿斯蒂(Asti)得到了正确的想法,但更好的方法是提供IScheduler参数而不是油门:

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

这将使运营下面这一点在UI线程(包括你的ShowProgressBar),直到SelectMany。

+0

这确实解决了问题!我使用的语法是.Throttle(TimeSpan.FromMilliseconds(500),CoreDispatcherScheduler.Default) – David

1

每个依赖项对象都要求对依赖项属性be made only on the Dispatcher thread进行任何更改。 Throttle正在使用不同的调度程序,因此在随后的Do组合器中对UI进行任何更改都会导致访问异常。

您可以解决此问题:

  1. 引起的调度副作用的任何操作之前添加ObserveOnDispatcher。可以选择使用另一个调度程序。
  2. 使用Dispatcher.Invoke通过调度程序执行副作用。例如,.Do(() => Dispatcher.Invoke(new Action(ShowProgressBar)))
+0

嗨,好吧,如果我在调用Do(ShowProgressBar)之前添加ObserveOnDispatcher(),ShowProgressBar永远不会被调用。在Win8中,调度程序是一个CoreDispatcher,并使用上面代码中使用的.RunAsync()。我的问题是,如果在该调用之前使用ObserveOnDispatcher(),代码永远不会被调用。 – David