Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf ReactiveUI调用线程无法访问此对象,因为另一个线程拥有它_Wpf_Reactiveui - Fatal编程技术网

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