ReactiveCollection交叉线程访问错误

时间:2012-12-04 07:55:10

标签: reactiveui

我从ReactiveCollection示例中获取了代码,以便在Silverlight 5中创建一个简单的搜索应用。

但是在返回搜索结果之后,当对ReactiveCollection“Stuff”的绑定被执行时,我得到一个交叉线程错误。当我在WPF中运行相同的代码时,它工作正常。如何确保在UIThread上完成绑定更新?

public class AppViewModel : ReactiveValidatedObject
{
    string _SearchTerm;
    public string SearchTerm
    {
        get { return _SearchTerm; }
        set { this.RaiseAndSetIfChanged(x => x.SearchTerm, ref _SearchTerm, value); }
    }

    public ReactiveAsyncCommand ExecuteSearch { get; protected set; }

    ObservableAsPropertyHelper<ReactiveCollection<string>> _Stuff;
    public ReactiveCollection<string> Stuff
    {
        get { return _Stuff.Value; }
    }

    public AppViewModel()
    {
        ExecuteSearch = new ReactiveAsyncCommand();

        var results = ExecuteSearch.RegisterAsyncFunction(term => DoSearch((string)term));

        this.ObservableForProperty(x => x.SearchTerm)
            .Throttle(TimeSpan.FromMilliseconds(800), RxApp.DeferredScheduler)
            .Select(x => x.Value).DistinctUntilChanged()
            .Where(x => !String.IsNullOrWhiteSpace(x))
            .Subscribe(ExecuteSearch.Execute);

        _Stuff = this.ObservableToProperty(results, x => x.Stuff); 
    }

    public static ReactiveCollection<string> DoSearch(string term)
    {
        return new ReactiveCollection<string>() { "One", "Two", "Three"};
    }
}

这是XAML

<UserControl x:Class="ReactiveUIPlay.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
Height="350" Width="525">

<Grid Margin="12">
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="Auto" />
  <ColumnDefinition Width="*" />
  <ColumnDefinition Width="Auto" />
 </Grid.ColumnDefinitions>

 <Grid.RowDefinitions>
  <RowDefinition Height="Auto" />
  <RowDefinition Height="*" />
 </Grid.RowDefinitions>

 <TextBlock FontSize="16" FontWeight="Bold" VerticalAlignment="Center"><Run Text="Search For:"/></TextBlock>
 <TextBox Grid.Column="1" Margin="6,0,0,0" Text="{Binding SearchTerm, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
 <ListBox Grid.ColumnSpan="3" Grid.Row="1" Margin="0,6,0,0" 
             ScrollViewer.HorizontalScrollBarVisibility="Disabled"
             ItemsSource="{Binding Stuff}" />

   

这是调用绑定到Stuff时的调用堆栈,就在异常之前。

>   ReactiveUIPlay!ReactiveUIPlay.AppViewModel.Stuff.get() Line 44  C#
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Windows.dll!System.Windows.CLRPropertyListener.Value.get() + 0x32 bytes  
System.Windows.dll!System.Windows.PropertyAccessPathStep.Value.get() + 0x14 bytes   
System.Windows.dll!System.Windows.PropertyPathListener.ReconnectPath() + 0x1d bytes 
System.Windows.dll!System.Windows.Data.Debugging.BindingBreakPoint.BreakOnSharedType.AnonymousMethod__3() + 0x14 bytes  
[Native to Managed Transition]  
[Managed to Native Transition]  
mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args) + 0x6b bytes  
mscorlib.dll!System.Delegate.DynamicInvoke(object[] args) + 0xb bytes   
BindingDebugging!MainPagexaml.BindingOperation(object BindingState) + 0x30 bytes    Unknown
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Windows.dll!System.Windows.Data.Debugging.BindingBreakPoint.BreakOnSharedType(System.Type emittedType, System.Windows.Data.Debugging.BindingDebugState debugState, int bindingNumber, int line, int column, System.Action callback) + 0xd5 bytes 
System.Windows.dll!System.Windows.Data.Binding.EnsureBreakPoint(System.Windows.Data.Debugging.BindingDebugState debugState, System.Action callback, bool canDelay) + 0x1ff bytes    
System.Windows.dll!System.Windows.Data.BindingExpression.OnSourcePropertyChanging(System.Action action) + 0x38 bytes    
System.Windows.dll!System.Windows.PropertyPathListener.RaisePropertyPathStepChanged(System.Windows.PropertyPathStep source) + 0x4b bytes    
System.Windows.dll!System.Windows.PropertyAccessPathStep.RaisePropertyPathStepChanged(System.Windows.PropertyListener source) + 0xc bytes   
System.Windows.dll!System.Windows.CLRPropertyListener.SourcePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs args) + 0x6a bytes    
System.Windows.dll!System.Windows.Data.WeakPropertyChangedListener.PropertyChangedCallback(object sender, System.ComponentModel.PropertyChangedEventArgs args) + 0x3d bytes 
ReactiveUI_SL5!ReactiveUI.ReactiveObject.raisePropertyChanged(string propertyName) + 0x12e bytes    
ReactiveUI_SL5!ReactiveUI.OAPHCreationHelperMixin.ObservableToProperty<ReactiveUIPlay.AppViewModel,ReactiveUI.ReactiveCollection<string>>.AnonymousMethod__0(ReactiveUI.ReactiveCollection<string> _) + 0x32 bytes  
ReactiveUI_SL5!ReactiveUI.ObservableAsPropertyHelper<ReactiveUI.ReactiveCollection<string>>..ctor.AnonymousMethod__0(ReactiveUI.ReactiveCollection<string> x) + 0x18e bytes 
System.Reactive.Core!System.Reactive.AnonymousSafeObserver<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x5a bytes  
System.Reactive.Core!System.Reactive.ScheduledObserver<ReactiveUI.ReactiveCollection<string>>.OnNextCore.AnonymousMethod__4() + 0x83 bytes  
System.Reactive.Core!System.Reactive.ScheduledObserver<ReactiveUI.ReactiveCollection<string>>.Run(object state, System.Action<object> recurse) + 0x105 bytes    
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.InvokeRec1<object>.AnonymousMethod__d(object state1) + 0x72 bytes    
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.InvokeRec1<object>(System.Reactive.Concurrency.IScheduler scheduler, System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>> pair) + 0x189 bytes  
System.Reactive.Core!System.Reactive.Concurrency.ImmediateScheduler.Schedule<System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>>>(System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>> state, System.Func<System.Reactive.Concurrency.IScheduler,System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>>,System.IDisposable> action) + 0xa0 bytes   
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.Schedule<object>(System.Reactive.Concurrency.IScheduler scheduler, object state, System.Action<object,System.Action<object>> action) + 0x1c3 bytes   
System.Reactive.Core!System.Reactive.ScheduledObserver<ReactiveUI.ReactiveCollection<string>>.EnsureActive() + 0x12b bytes  
System.Reactive.Core!System.Reactive.ObserveOnObserver<ReactiveUI.ReactiveCollection<string>>.OnNextCore(ReactiveUI.ReactiveCollection<string> value) + 0x2f bytes  
System.Reactive.Core!System.Reactive.ObserverBase<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x3d bytes   
System.Reactive.Linq!System.Reactive.Subjects.Subject<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x50 bytes   
ReactiveUI_SL5!ReactiveUI.ScheduledSubject<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x2f bytes  
System.Reactive.Linq!System.Reactive.Linq.Observable.AsObservable<ReactiveUI.ReactiveCollection<string>>._.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x7c bytes 
System.Reactive.Linq!System.Reactive.Linq.Observable.DistinctUntilChanged<ReactiveUI.ReactiveCollection<string>,ReactiveUI.ReactiveCollection<string>>._.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x29a bytes  
System.Reactive.Core!System.Reactive.SafeObserver<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x90 bytes   
System.Reactive.Core!System.Reactive.ScheduledObserver<ReactiveUI.ReactiveCollection<string>>.OnNextCore.AnonymousMethod__4() + 0x83 bytes  
System.Reactive.Core!System.Reactive.ScheduledObserver<ReactiveUI.ReactiveCollection<string>>.Run(object state, System.Action<object> recurse) + 0x105 bytes    
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.InvokeRec1<object>.AnonymousMethod__d(object state1) + 0x72 bytes    
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.InvokeRec1<object>(System.Reactive.Concurrency.IScheduler scheduler, System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>> pair) + 0x189 bytes  
System.Reactive.Core!System.Reactive.Concurrency.ImmediateScheduler.Schedule<System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>>>(System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>> state, System.Func<System.Reactive.Concurrency.IScheduler,System.Reactive.Concurrency.Scheduler.Pair<object,System.Action<object,System.Action<object>>>,System.IDisposable> action) + 0xa0 bytes   
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.Schedule<object>(System.Reactive.Concurrency.IScheduler scheduler, object state, System.Action<object,System.Action<object>> action) + 0x1c3 bytes   
System.Reactive.Core!System.Reactive.ScheduledObserver<ReactiveUI.ReactiveCollection<string>>.EnsureActive() + 0x12b bytes  
System.Reactive.Core!System.Reactive.ObserveOnObserver<ReactiveUI.ReactiveCollection<string>>.OnNextCore(ReactiveUI.ReactiveCollection<string> value) + 0x2f bytes  
System.Reactive.Core!System.Reactive.ObserverBase<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x3d bytes   
System.Reactive.Linq!System.Reactive.Subjects.Subject<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x50 bytes   
ReactiveUI_SL5!ReactiveUI.ScheduledSubject<ReactiveUI.ReactiveCollection<string>>.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x2f bytes  
System.Reactive.Linq!System.Reactive.Linq.Observable.AsObservable<ReactiveUI.ReactiveCollection<string>>._.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x7c bytes 
System.Reactive.Linq!System.Reactive.Linq.Observable.Merge<ReactiveUI.ReactiveCollection<string>>._.?.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0xac bytes  
System.Reactive.Linq!System.Reactive.Linq.Observable.Finally<ReactiveUI.ReactiveCollection<string>>._.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x7c bytes  
System.Reactive.Linq!System.Reactive.Linq.Observable.Catch<ReactiveUI.ReactiveCollection<string>,System.Exception>._.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x7c bytes   
System.Reactive.Linq!System.Reactive.Linq.Observable.AsObservable<ReactiveUI.ReactiveCollection<string>>._.OnNext(ReactiveUI.ReactiveCollection<string> value) + 0x7c bytes 
System.Reactive.Linq!System.Reactive.Subjects.AsyncSubject<ReactiveUI.ReactiveCollection<string>>.OnCompleted() + 0x234 bytes   
System.Reactive.Linq!System.Reactive.Linq.QueryLanguage.ToAsync<object,ReactiveUI.ReactiveCollection<string>>.AnonymousMethod__d0() + 0xba bytes    
System.Reactive.Core!System.Reactive.Concurrency.Scheduler.Invoke(System.Reactive.Concurrency.IScheduler scheduler, System.Action action) + 0x2e bytes  
System.Reactive.PlatformServices!System.Reactive.Concurrency.ThreadPoolScheduler.Schedule<System.Action>.AnonymousMethod__0(object _) + 0x7d bytes  
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state) + 0x3e bytes 
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x97 bytes  
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x5a bytes 
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x1b3 bytes  
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x5 bytes 
[Native to Managed Transition]  
[Appdomain Transition]  
[Native to Managed Transition]

这是RxApp.DeferredScheduler的类型 - System.Reactive.Concurrency.IScheduler

RxApp.DeferredScheduler

1 个答案:

答案 0 :(得分:1)

您的问题出在Throttle行 - 由于您未指定IScheduler,因此Rx采用TaskPoolScheduler,即Bad™。将其更改为:

.Throttle(TimeSpan.FromMilliseconds(800), RxApp.DeferredScheduler)