2017-10-04 2 views
4

Ich verwende die neueste Vorabversion von RxUI 8, aber ich denke, dass dies in früheren Versionen passieren würde.ReactiveUI Befehl Nebenläufigkeit (WebClient)

ich diesen ReactiveCommand in meinem WPF-Anwendung definiert haben:

GetWebsiteCommand = ReactiveCommand.CreateFromTask(DownloadString); 

private async Task<string> DownloadString() 
{ 
    using (var client = new WebClient()) 
    { 
     return await client.DownloadStringTaskAsync("http://www.google.es"); 
    } 
} 

Wenn der Befehl ausgeführt wird, wird die folgende Ausnahme ausgelöst:

System.InvalidOperationException‘bei System.Reactive.Core. dll: Der aufrufende Thread kann dieses Objekt nicht zugreifen, da ein anderer Thread es

besitzt 10

Warum passiert das? Ich erstelle keinen neuen Thread!

Dies ist der Stack-Trace:

System.InvalidOperationException‘bei System.Reactive.Core.dll: Der Aufruf Thread dieses Objekt nicht zugreifen, da ein anderer Thread es

at System.Windows.Threading.Dispatcher.VerifyAccess() 
    at System.Windows.DependencyObject.GetValue(DependencyProperty dp) 
    at System.Windows.Controls.Primitives.ButtonBase.get_Command() 
    at System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute() 
    at System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object sender, EventArgs e) 
    at System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender, EventArgs e) 
    at ReactiveUI.ReactiveCommand.OnCanExecuteChanged() 
    at ReactiveUI.ReactiveCommand`2.<.ctor>b__9_5(Boolean _) 
    at System.Reactive.AnonymousSafeObserver`1.OnNext(T value) 
    at System.Reactive.Linq.ObservableImpl.RefCount`1._.OnNext(TSource value) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive(Int32 count) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive() 
    at System.Reactive.Subjects.ReplaySubject`1.ReplayBase.OnNext(T value) 
    at System.Reactive.Subjects.ReplaySubject`1.OnNext(T value) 
    at System.Reactive.Linq.ObservableImpl.AsObservable`1._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.CombineLatest`3._.S.OnNext(TSecond value) 
    at System.Reactive.Linq.ObservableImpl.RefCount`1._.OnNext(TSource value) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive(Int32 count) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive() 
    at System.Reactive.Subjects.ReplaySubject`1.ReplayBase.OnNext(T value) 
    at System.Reactive.Subjects.ReplaySubject`1.OnNext(T value) 
    at System.Reactive.Linq.ObservableImpl.AsObservable`1._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.Concat`1._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.Select`2._.OnNext(TSource value) 
    at System.Reactive.SafeObserver`1.OnNext(TSource value) 
    at System.Reactive.ScheduledObserver`1.Dispatch(ICancelable cancel) 
    at System.Reactive.Concurrency.Scheduler.<>c.<ScheduleLongRunning>b__72_0(Action`1 a, ICancelable c) 
    at System.Reactive.Concurrency.DefaultScheduler.LongRunning.<>c__DisplayClass1_0`1.<ScheduleLongRunning>b__0(Object arg) 
    at System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.<>c__DisplayClass7_0.<StartThread>b__0() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 
besitzt
+0

Sie erstellen keinen neuen Thread? Vielleicht kennen Sie das Konzept von Task nicht. Lesen Sie [diesen Artikel] (https://docs.microsoft.com/en-us/dotnet/csharp/async) für Informationen –

+0

@CamiloTerevinto. Nein, ich erstelle keinen neuen Thread. Wo erstelle ich einen Thread? Soweit ich weiß, beinhaltet eine Aufgabe NICHT die Erstellung eines Threads. Wissen Sie, ob die WebClient.DownloadStringTaskAsync-Methode die Aufgabe in einem anderen Thread ausführt? – SuperJMN

+0

@CamiloTerevinto Kannst du mir bitte sagen, ob Task.FromResult (() => 1) auf einem neuen Thread läuft? Stoppen Sie die Abstimmung ohne Grund, bitte, und geben Sie nützliche Antworten. Ansonsten lass es andere tun. – SuperJMN

Antwort

2

Gemessen an der Stack-Trace übergeben Sie eine canExecute Pipeline in den Befehl. Für jede Pipeline, die Sie bereitstellen, müssen Sie sicherstellen, dass sie den richtigen Thread verwendet. Wenn es in einem Hintergrundthread abhakt, werden die Befehle CanExecute Ereignis in demselben Thread ankreuzen, und die Benutzeroberfläche wird daher versuchen, die IsEnabled-Eigenschaft auf dem zugeordneten Button aus dem falschen Thread zu aktualisieren.

So müssen Sie wahrscheinlich einen ObserveOn Anruf gegen Ihre canExecute Pipeline hinzufügen.

UPDATE: beantwortet here.

+0

Danke, Kent! Aber ich gebe keine CanExecute-Pipeline weiter. Der Befehl wird mit der Zeile 'ReactiveCommand.CreateFromTask (DownloadString) 'erzeugt;' Ich gebe also nur die Aufgabe weiter. Können Sie bitte den Code ausführen? Mit diesen einfachen Linien können Sie das Problem reproduzieren. – SuperJMN