2013-05-16 42 views
0

如果我使用的代碼綁定的背後,在變化IsBusy得到一個錯誤的點擊後ReactiveUI調用線程不能訪問該對象

"The calling thread cannot access this object because a different thread owns it" 

XAML:

<Button x:Name="AsyncCommand" 
        Height="20" 
        Content="PushAsync"/> 
<ProgressBar x:Name="IsBusy" 
       Height="20"/> 

CS:

this.Bind(ViewModel, x => x.IsBusy, x => x.IsBusy.IsIndeterminate); 
this.BindCommand(ViewModel, x => x.AsyncCommand, x => x.AsyncCommand); 

視圖模型:

public class TestViewModel : ReactiveObject 
    { 
     public TestViewModel() 
     { 
      AsyncCommand = new ReactiveAsyncCommand(); 
      AsyncCommand 
       .RegisterAsyncFunction(x => 
       { IsBusy = true; Thread.Sleep(3000); return "Ok"; }) 
       .Subscribe(x => { IsBusy = false; }); 
     } 

     private bool isBusy; 

     public bool IsBusy 
     { 
      get { return isBusy; } 
      set { this.RaiseAndSetIfChanged(x => x.IsBusy, ref isBusy, value); } 
     } 
     public ReactiveAsyncCommand AsyncCommand { get; protected set; } 
    } 

但是,如果我做一個綁定在XAML中所有的作品,像這樣:

CS:

DataContext = new TestViewModel(); 

XAML:

<Button x:Name="AsyncCommand" 
        Height="20" 
        Content="PushAsync" 
        Command="{Binding AsyncCommand}"/> 
<ProgressBar x:Name="IsBusy" 
       Height="20" 
       IsIndeterminate="{Binding IsBusy}"/> 

這究竟是爲什麼?

回答

1

試試這個:

public TestViewModel() 
{ 
    AsyncCommand = new ReactiveAsyncCommand(); 
    AsyncCommand.Subscribe(_ => IsBusy = true); 

    AsyncCommand 
     .RegisterAsyncFunction(x => 
     { Thread.Sleep(3000); return "Ok"; }) 
     .Subscribe(x => { IsBusy = false; }); 
} 

甚至更​​好:

ObservableAsPropertyHelper<bool> _IsBusy; 
public bool IsBusy { 
    get { return _IsBusy.Value; } 
} 

public TestViewModel() 
{ 
    AsyncCommand = new ReactiveAsyncCommand(); 
    AsyncCommand 
     .RegisterAsyncFunction(x => 
     { Thread.Sleep(3000); return "Ok"; }) 
     .Subscribe(x => { /* do a thing */ }); 

    AsyncCommand.ItemsInFlight 
     .Select(x => x > 0 ? true : false) 
     .ToProperty(this, x => x.IsBusy); 
} 
0

我假設你的視圖模型屬性實現類同此:

public TestViewModel ViewModel 
{ 
    get { return (TestViewModel)DataContext; } 
    set { DataContext = value; } 
} 

在這種情況下,當你點擊從RegisterAsyncFunction按鈕,lambda函數被調用於非UI線程。在IsBusy = false指令中,ReactiveUI調用ViewModel屬性,該屬性嘗試在非UI線程上獲取DataContext,這會導致InvalidOperationException

如果將ViewModel綁定到Xaml中的View,則不會調用ViewModel屬性。

爲了解決這個問題,你應該使用Dispatcher.Invoke調用IsBusy = false

AsyncCommand 
    .RegisterAsyncFunction(x => 
    { 
     Application.Current.Dispatcher.Invoke(() =>IsBusy = true); 
     Thread.Sleep(3000); 
     return "Ok"; 
    })' 
+0

這是ReactiveUI不正確的意見(儘管你有核心錯誤是正確的) –

相關問題