我从 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