2012-09-22 52 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