Wpf ReactiveUI调用线程无法访问此对象,因为另一个线程拥有它
如果我在代码隐藏中使用绑定,那么在单击“更改”按钮后出现错误是很忙的Wpf ReactiveUI调用线程无法访问此对象,因为另一个线程拥有它,wpf,reactiveui,Wpf,Reactiveui,如果我在代码隐藏中使用绑定,那么在单击“更改”按钮后出现错误是很忙的 "The calling thread cannot access this object because a different thread owns it" xaml: 视图模型: public class TestViewModel : ReactiveObject { public TestViewModel() { AsyncCommand = ne
"The calling thread cannot access this object because a different thread owns it"
xaml:
视图模型:
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中绑定,所有功能都会正常工作,如下所示:
政务司司长:
xaml:
为什么会发生这种情况?我假设您的ViewModel属性的实现与此类似:
public TestViewModel ViewModel
{
get { return (TestViewModel)DataContext; }
set { DataContext = value; }
}
在这种情况下,当您单击按钮时,将在非UI线程上调用RegisterAsyncFunction中的lambda函数。在IsBusy=false指令中,ReactiveUI调用ViewModel属性,该属性尝试在非UI线程上获取DataContext,这会导致InvalidOperationException
如果将ViewModel绑定到Xaml中的视图,则不会调用ViewModel属性
要修复此代码,应使用调用IsBusy=false:
试试这个:
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);
}
这对于ReactiveUI是不正确的建议,尽管您已经纠正了核心错误。您不想让VM了解应用程序。如何从WhenyValue调用UI线程上的同步方法?找到我的答案。非常感谢。
<Button x:Name="AsyncCommand"
Height="20"
Content="PushAsync"
Command="{Binding AsyncCommand}"/>
<ProgressBar x:Name="IsBusy"
Height="20"
IsIndeterminate="{Binding IsBusy}"/>
public TestViewModel ViewModel
{
get { return (TestViewModel)DataContext; }
set { DataContext = value; }
}
AsyncCommand
.RegisterAsyncFunction(x =>
{
Application.Current.Dispatcher.Invoke(() =>IsBusy = true);
Thread.Sleep(3000);
return "Ok";
})'
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);
}