2017-06-02 37 views
0

我有一個ReactiveCommand刷新數據並綁定到XAML中的按鈕。該功能工作正常,但我也想在計時器上執行該命令。來自Observable.Timer的InvokeCommand引起跨線程問題

我有下面的代碼 - SetupAutoRefresh是從我的虛擬機的構造函數調用,但是當可觀察火災,我得到的消息的異常:「,因爲不同的線程擁有它調用線程不能訪問該對象。 「

VM:

private void SetupAutoRefresh() { 
    Observable.Timer(TimeSpan.FromSeconds(5)) 
      .Select(_ => Unit.Default) 
      .ObserveOn(RxApp.MainThreadScheduler) 
      .InvokeCommand(RefreshData); 

    RefreshData = ReactiveCommand.CreateFromTask(Refresh); 
} 

private async Task Refresh() 
{ 
    var updatedData = await _repository.GetAll(); 
    Data.Merge(updatedData); 
} 

private ReactiveCommand<Unit, Unit> _refreshData; 
public ReactiveCommand<Unit, Unit> RefreshData 
{ 
    get { return _refreshData; } 
    set { this.RaiseAndSetIfChanged(ref _refreshData, value); } 
} 

private IReactiveList<Model> _data; 
public IReactiveList<Model> Data 
{ 
    get { return _data; } 
    set { this.RaiseAndSetIfChanged(ref _data, value); } 
} 

XAML:

<Button Grid.Column="2" 
     Command="{Binding RefreshData}" 
     Style="{StaticResource ToolbarButtonTheme}" 
     Content="{StaticResource RefreshToolbarIcon}" 
     ToolTip="Refresh Search"/> 

調試輸出提供此堆棧跟蹤:

在System.Windows.Threading.Dispatcher.VerifyAccess() 在系統.Windows.DependencyObject.GetValue(DependencyProperty dp) 在System.Windows.Controls.Primitives.ButtonBase.get_Command() 在System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute() 在System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(對象>發件人,EventArgs的) 在 System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(對象發件人,EventArgs的) 在ReactiveUI.ReactiveCommand.OnCanExecuteChanged()在C:\項目\ reactiveui \ SRC \ ReactiveUI \ ReactiveCommand.cs:線628

我已經嘗試了許多不同的嘗試在RxApp.MainThreadScheduler上進行調度,但沒有任何喜悅 - ObserveOn,SubscribeOn,設置輸出調度程序......沒有任何變化無論如何,我有很多希望。

感覺就像我在這裏錯過了一些明顯的東西,但整個下午都撞在了一堵磚牆上。 RxUI中這種情況是可能的嗎?

回答

0

想通了這個問題,它返回到你的UI線程上 - 看起來像可觀測需要在UI線程上創建。我錯過了原始帖子,但SetupAutoRefresh方法是從另一個異步方法調用的,該方法在事先等待期間切換了上下文。

0

Refresh方法在後臺線程上運行;您無法修改該方法中的數據綁定屬性。

試試這個:

private void SetupAutoRefresh() { 
    Observable.Timer(TimeSpan.FromSeconds(5)) 
      .Select(_ => Unit.Default) 
      // remove ObserveOn here; the Command will run on the background 
      .InvokeCommand(RefreshData); 

    RefreshData = ReactiveCommand.CreateFromTask(Refresh); 
    // RefreshData.Subscribe is guaranteed to run on the UI thread 
    RefreshData.Subscribe(listOfModels => Data.Merge(listOfModels)) 
} 

private async Task Refresh() 
{ 
    // all this method does is deliver a list of models 
    return await _repository.GetAll(); 
} 

// return IEnumerable<Model> from the command 
public ReactiveCommand<Unit, IEnumerable<Model>> RefreshData 

現在,您只需ReactiveCommand獲取新的數據,並在Subscribe :)

+0

謝謝,我也試過這個 - 但它不起作用,因爲它沒有解決潛在的問題。它不是所抱怨的數據綁定屬性,而是綁定到按鈕的命令。特別是在命令執行過程中CanExecute發生改變(可能是假)。請參閱我的原始帖子中的堆棧跟蹤。 – Mike

+0

好吧,我已經複製了您的原始代碼並構建了依賴項([MainViewModel.cs](https://gist.github.com/domyd/73895b166b160b9d09d5902e24bd97ef),[MainWindow.xaml](https:// gist)。 github.com/domyd/350e8aef743d348e183b5c496391e220))。這對我來說非常合適。我改變的唯一的事情是在'SetupAutoRefresh'中交換'Observable'和'ReactiveCommand'的創建順序,否則它會崩潰。我也用'Add'替換了'Merge'。也許這有幫助? – domyd