【发布时间】:2013-12-19 16:44:07
【问题描述】:
我正在尝试使用 Caliburn.Micro.ReactiveUI 编写一个非常简单的示例,此示例结合了 Basic Configuration, Actions and Conventions sample from the Caliburn.Micro Documentation 和 ReactiveUI.Sample.Commands sample。我遇到的问题是,当调用任何命令时,对于DisplayCommand 和StartAsyncCommand,都会抛出InvalidOperationException,说明调用线程无法访问该对象,因为不同的线程拥有它。下面我包含了 View 和 ViewModel 的代码,整个示例位于 GitHub 代码现在包含下面 Paul 建议的修复。
在互联网上搜索没有得到任何信息。我想我遗漏了一些明显的东西,非常感谢任何帮助。
视图模型:
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; }
}
观点:
<Window x:Class="CaliburnMicroReactiveUI.Sample.Commands.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Expander
IsExpanded="True"
Header="Simple Command">
<StackPanel>
<TextBox
Text="{Binding PersonName, UpdateSourceTrigger=PropertyChanged}" />
<Button
Command="{Binding DisplayCommand}"
Content="Display" />
</StackPanel>
</Expander>
<Expander
IsExpanded="True"
Header="Async Command">
<StackPanel>
<Button Command="{Binding StartAsyncCommand}" Content="Start" />
<ProgressBar Value="{Binding Progress, Mode=OneWay}" Height="20"/>
</StackPanel>
</Expander>
</StackPanel>
</Window>
显示按钮生成以下堆栈跟踪:
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()
【问题讨论】:
标签: multithreading caliburn.micro reactiveui caliburn.micro.reactiveui