Multithreading 使用Caliburn.Micro.ReactiveUI 1.2.2时,不正确的线程访问UI对象

Multithreading 使用Caliburn.Micro.ReactiveUI 1.2.2时,不正确的线程访问UI对象,multithreading,caliburn.micro,reactiveui,caliburn.micro.reactiveui,Multithreading,Caliburn.micro,Reactiveui,Caliburn.micro.reactiveui,我正在尝试使用Caliburn.Micro.ReactiveUI编写一个非常简单的示例。此示例结合了。我遇到的问题是,当调用任何命令时,因此对于DisplayCommand和StartAsyncCommand,都会抛出一个InvalidOperationException,说明调用线程无法访问此对象,因为另一个线程拥有它。下面我已经包括了视图和视图模型的代码,整个示例都在代码中,现在包含了Paul建议的修复 搜索互联网没有得到任何信息。我想我遗漏了一些明显的东西,非常感谢您的帮助 viewmod

我正在尝试使用Caliburn.Micro.ReactiveUI编写一个非常简单的示例。此示例结合了。我遇到的问题是,当调用任何命令时,因此对于
DisplayCommand
StartAsyncCommand
,都会抛出一个
InvalidOperationException
,说明调用线程无法访问此对象,因为另一个线程拥有它。下面我已经包括了视图和视图模型的代码,整个示例都在代码中,现在包含了Paul建议的修复

搜索互联网没有得到任何信息。我想我遗漏了一些明显的东西,非常感谢您的帮助

viewmodel:

public class ShellViewModel : ReactivePropertyChangedBase, IShell
{
    private string personName;

    public ShellViewModel(IMessageBoxService messageBoxService)
    {
        DisplayCommand = new ReactiveCommand(this.WhenAny(x => x.PersonName, x => !string.IsNullOrEmpty(x.Value)));
        DisplayCommand.Subscribe(_ => messageBoxService.ShowMessageBox("You clicked on DisplayCommand: Name is " + PersonName));

        var localProgress = new Subject<int>();
        localProgress.ToProperty(this, x => x.Progress, out progress);

        StartAsyncCommand = new ReactiveCommand();
        StartAsyncCommand.RegisterAsyncAction(_ =>
        {
            var currentProgress = 0;
            localProgress.OnNext(currentProgress);
            while (currentProgress <= 100)
            {
                localProgress.OnNext(currentProgress += 10);
                Thread.Sleep(100);
            }
        });
    }

    public IReactiveCommand DisplayCommand { get; protected set; }

    public string PersonName
    {
        get { return personName; }
        set
        {
            this.RaiseAndSetIfChanged(ref personName, value);
        }
    }

    private ObservableAsPropertyHelper<int> progress;
    public int Progress
    {
        get { return progress.Value; }
    }

    public IReactiveCommand StartAsyncCommand { get; protected set; }
}
公共类ShellViewModel:ReactivePropertyChangedBase,IShell
{
私有字符串personName;
公共ShellViewModel(IMessageBoxService messageBoxService)
{
DisplayCommand=newreactivecommand(this.WhenAny(x=>x.PersonName,x=>!string.IsNullOrEmpty(x.Value));
DisplayCommand.Subscribe(=>messageBoxService.ShowMessageBox(“您单击了DisplayCommand:Name是“+PersonName));
var localProgress=新主题();
ToProperty(this,x=>x.Progress,out Progress);
StartAsyncCommand=new ReactiveCommand();
StartAsyncCommand.RegisterAsyncAction(=>
{
var currentProgress=0;
localProgress.OnNext(当前进度);

而(currentProgress您的问题是您正在更改RegisterSyncAction中的
Progress
,这明确保证它不会在UI线程上运行。以下是一种更好的方法:

ObservableAsPropertyHelper<int> _progress;
public int Progress 
{
    get { return _progress.Value; }
}

public ShellViewModel(IMessageBoxService messageBoxService)
{
    DisplayCommand = new ReactiveCommand(this.WhenAny(x => x.PersonName, x => !string.IsNullOrEmpty(x.Value)));
    DisplayCommand.Subscribe(_ => messageBoxService.ShowMessageBox("You clicked on DisplayCommand: Name is " + PersonName));

    var progress = new Subject<int>();
    progress.ToProperty(this, x => x.Progress, out _progress);

    StartAsyncCommand = new ReactiveCommand();
    StartAsyncCommand.RegisterAsyncAction(_ =>
    {
        var currentProgress = 0;
        progress.OnNext(currentProgress);
        while (currentProgress <= 100)
        {
            progress.OnNext(currentProgress += 10);
            Thread.Sleep(100);
        }
    });
}
ObservablePropertyHelper\u进度;
公共信息技术进步
{
获取{return\u progress.Value;}
}
公共ShellViewModel(IMessageBoxService messageBoxService)
{
DisplayCommand=newreactivecommand(this.WhenAny(x=>x.PersonName,x=>!string.IsNullOrEmpty(x.Value));
DisplayCommand.Subscribe(=>messageBoxService.ShowMessageBox(“您单击了DisplayCommand:Name是“+PersonName));
var progress=新主题();
progress.ToProperty(this,x=>x.progress,out\u progress);
StartAsyncCommand=new ReactiveCommand();
StartAsyncCommand.RegisterAsyncAction(=>
{
var currentProgress=0;
progress.OnNext(当前进度);

虽然(currentProgress我已经查看了您的GitHub存储库,看起来您刚刚添加了Caliburn.Micro.ReactiveUI包。这意味着您只有ReactiveUI核心,并且缺少特定于平台的扩展。如果您添加了该包,一切都会更好(不过,您仍然需要初始化messageBoxService!).

谢谢您的解释,显然我的问题不够明确,但我得到了DisplayCommand和StartAsyncCommand的例外。我更新了问题以使其更清楚,您对DisplayCommand有什么建议吗?我无法编译您的代码:
System.Reactive.Subjects.Subject
does不包含
TopProperty
的定义和最佳扩展方法重载
ReactiveUI.OAPHCreationHelperMixin.TopProperty(System.IObservable、TObj、System.Linq.Expressions.Expression、out ReactiveUI.ObservablesPropertyHelper、TRet、System.Reactive.Concurrency.IsScheduler)
有一些无效参数。哎呀,将“ref”改为“out”,这样做了,问题仍然存在,我已经用堆栈跟踪更新了问题,并启动了项目。谢谢,这解决了所有问题。
ReactiveUI Xaml
应该是
Caliburn.Micro.ReactiveUI
的依赖项吗?是的,几乎可以肯定
ReactiveUI Xaml
不是Caliburn.Micro.ReactiveUI的技术依赖项,但添加依赖项可能是有意义的……老实说,我不确定,
ReactiveUI
的每个包的确切用途。@PaulBetts,您愿意解释一下它们的区别吗?谢谢!许多RxUI包都是出于向后兼容的原因而保留在那里的(即,现在只是元包),所以人们不会崩溃。你实际上应该关心的是ReactiveUI核心和ReactiveUI平台hanks,这就是我所猜测的…所以,剩下的问题是:在一个包中引用ReactiveUI平台,而不需要它,仅仅因为应用程序需要它,这有意义吗?奇怪的是,我有一个exact反对Calibrun.Micro团队提出的仅在包()中引用Caliburn.Micro.Core的请求。。。
System.Windows.Threading.Dispatcher.VerifyAccess()
System.Windows.DependencyObject.GetValue(DependencyProperty dp)
System.Windows.Controls.Primitives.ButtonBase.get_Command()
System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object sender, EventArgs e)
System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender, EventArgs e)
ReactiveUI.ReactiveCommand.raiseCanExecuteChanged(EventArgs e)
ReactiveUI.ReactiveCommand.<.ctor>b__5()
System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
System.Reactive.Concurrency.DefaultScheduler.<>c__DisplayClass1`1.<Schedule>b__0(Object _)
System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.<>c__DisplayClass1.<QueueUserWorkItem>b__0(Object _)
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading.ThreadPoolWorkQueue.Dispatch()
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
System.Windows.Threading.Dispatcher.VerifyAccess()
System.Windows.DependencyObject.GetValue(DependencyProperty dp)
System.Windows.Controls.Primitives.ButtonBase.get_Command()
System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object sender, EventArgs e)
System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender, EventArgs e)
ReactiveUI.ReactiveCommand.raiseCanExecuteChanged(EventArgs e)
ReactiveUI.ReactiveCommand.<.ctor>b__5()
System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
System.Reactive.Concurrency.DefaultScheduler.<>c__DisplayClass1`1.<Schedule>b__0(Object _)
System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.<>c__DisplayClass1.<QueueUserWorkItem>b__0(Object _)
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading.ThreadPoolWorkQueue.Dispatch()
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
ObservableAsPropertyHelper<int> _progress;
public int Progress 
{
    get { return _progress.Value; }
}

public ShellViewModel(IMessageBoxService messageBoxService)
{
    DisplayCommand = new ReactiveCommand(this.WhenAny(x => x.PersonName, x => !string.IsNullOrEmpty(x.Value)));
    DisplayCommand.Subscribe(_ => messageBoxService.ShowMessageBox("You clicked on DisplayCommand: Name is " + PersonName));

    var progress = new Subject<int>();
    progress.ToProperty(this, x => x.Progress, out _progress);

    StartAsyncCommand = new ReactiveCommand();
    StartAsyncCommand.RegisterAsyncAction(_ =>
    {
        var currentProgress = 0;
        progress.OnNext(currentProgress);
        while (currentProgress <= 100)
        {
            progress.OnNext(currentProgress += 10);
            Thread.Sleep(100);
        }
    });
}