我有一个ReactiveCommand刷新数据并绑定到XAML中的Button。功能正常,但我也想在计时器上执行命令。
我有以下代码 - 我的VM中的ctor调用了SetupAutoRefresh,但是当Observable触发时,我收到一条消息的异常:"调用线程因为不同而无法访问此对象线程拥有它。"
VM:
private void SetupAutoRefresh() {
Observable.Timer(TimeSpan.FromSeconds(5))
.Select(_ => Unit.Default)
.ObserveOn(RxApp.MainThreadScheduler)
.InvokeCommand(RefreshData);
RefreshData = ReactiveCommand.CreateFromTask(Refresh);
}
private async Task Refresh()
{
var updatedData = await _repository.GetAll();
Data.Merge(updatedData);
}
private ReactiveCommand<Unit, Unit> _refreshData;
public ReactiveCommand<Unit, Unit> RefreshData
{
get { return _refreshData; }
set { this.RaiseAndSetIfChanged(ref _refreshData, value); }
}
private IReactiveList<Model> _data;
public IReactiveList<Model> Data
{
get { return _data; }
set { this.RaiseAndSetIfChanged(ref _data, value); }
}
XAML:
<Button Grid.Column="2"
Command="{Binding RefreshData}"
Style="{StaticResource ToolbarButtonTheme}"
Content="{StaticResource RefreshToolbarIcon}"
ToolTip="Refresh Search"/>
Debug输出提供了这个堆栈跟踪:
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&gt; sender,EventArgs e) 在 System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender,EventArgs e) 在C:\ projects \ reactiveui \ src \ ReactiveUI \ ReactiveCommand.cs中的ReactiveUI.ReactiveCommand.OnCanExecuteChanged():第628行
我尝试过尝试在RxApp.MainThreadScheduler上安排此操作的许多不同变体,但没有任何乐趣 - ObserveOn,SubscribeOn,设置输出调度程序......无论如何我都没有希望。
感觉我在这里错过了一些明显的东西,但整个下午一直在我的头撞墙。当然这种情况在RxUI中是可能的吗?
答案 0 :(得分:0)
Refresh
方法在后台线程上运行;你不能修改那个方法中的数据绑定属性。
试试这个:
private void SetupAutoRefresh() {
Observable.Timer(TimeSpan.FromSeconds(5))
.Select(_ => Unit.Default)
// remove ObserveOn here; the Command will run on the background
.InvokeCommand(RefreshData);
RefreshData = ReactiveCommand.CreateFromTask(Refresh);
// RefreshData.Subscribe is guaranteed to run on the UI thread
RefreshData.Subscribe(listOfModels => Data.Merge(listOfModels))
}
private async Task Refresh()
{
// all this method does is deliver a list of models
return await _repository.GetAll();
}
// return IEnumerable<Model> from the command
public ReactiveCommand<Unit, IEnumerable<Model>> RefreshData
现在,您的ReactiveCommand
只是抓取新数据,并在Subscribe
内的UI线程上将其返回给您:)
答案 1 :(得分:0)
找出问题 - 看起来需要在UI线程上创建Observable。我错过了原帖,但是SetupAutoRefresh方法是从另一个异步方法中调用的,该方法在之前的等待中切换了上下文。