我已經構建了一個小型日誌記錄GUI來幫助調試主應用程序。它需要在它自己的線程上運行,以便在主UI無響應時不會被阻止。記錄窗口的一部分目的是找出主窗口爲什麼沒有響應。如何正確使用ReactiveUI :: WhenAnyValue替代Windows線程?
新窗口通過此方法啓動。
public static Task<T> CreateAndShowStaWindow<T>(Func<T> factory) where T:Window
{
var windowResult = new TaskCompletionSource<T>();
var newWindowThread = new Thread(() =>
{
var window = factory();
window.Show();
windowResult.SetResult(window);
window.Events().Closed.Subscribe(_ => window.Dispatcher.InvokeShutdown());
System.Windows.Threading.Dispatcher.Run();
});
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
newWindowThread.Name = "STA WPF";
return windowResult.Task;
}
窗口裏面我有一個文本框
<TextBox x:Name="FilterText"/>
我希望監視使用ReactiveUI WhenAnyValue變化
this
.WhenAnyValue(p => p.FilterText.Text)
.Subscribe(Console.WriteLine);
現在我確信上述呼叫到WhenAnyValue是在新的STA線程上運行。我可以在調試器中檢查它。
和
如果我讓程序繼續,我得到
InvalidOperationException異常:因爲不同的線程擁有它調用線程不能訪問該對象。在「MAIN」線程,而不是「STA WPF」線程,並在在堆棧
ReactiveUI.dll!ReactiveUI.Reflection.TryGetValueForPropertyChain<object>(out object changeValue, object current, System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression> expressionChain) Line 129 ReactiveUI.dll!ReactiveUI.ReactiveNotifyPropertyChangedMixin.observedChangeFor(System.Linq.Expressions.Expression expression, ReactiveUI.IObservedChange<object, object> sourceChange) Line 134 ReactiveUI.dll!ReactiveUI.ReactiveNotifyPropertyChangedMixin.nestedObservedChanges(System.Linq.Expressions.Expression expression, ReactiveUI.IObservedChange<object, object> sourceChange, bool beforeChange) Line 142 ReactiveUI.dll!ReactiveUI.ReactiveNotifyPropertyChangedMixin.SubscribeToExpressionChain.AnonymousMethod__1(ReactiveUI.IObservedChange<object,> object> y) Line 104
使用WPF這點發生
這個例外是不允許跨線程訪問WPF依賴項屬性。問題是爲什麼ReactiveUI交叉線程訪問?
請注意,錯誤是而不是發生在Console.WriteLine
作爲傳遞給訂閱的回調。它發生在「內部」代碼中,因爲它試圖讀取TextBox
的Text
屬性。添加
this
.WhenAnyValue(p => p.FilterText.Text)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(Console.WriteLine);
不能解決問題。同樣沒有
this
.WhenAnyValue(p => p.FilterText.Text)
.SubscribeOn(DispatcherScheduler.Current)
.Subscribe(Console.WriteLine);
作爲santiy檢查,如果我刪除從代碼中調用WhenAnyValue然後我沒有得到這個錯誤。
似乎ReactiveUI正在與它應該操作的同步上下文混淆。但也許我做錯了什麼。有沒有解決方案/解決這個問題的方法?
編輯
重現您將需要調用的應用程序啓動初期插入到
Locator.CurrentMutable.InitializeReactiveUI();
一些點的誤差。複製錯誤的項目就在這裏。
https://github.com/bradphelan/RxUIBug1375
downvoter會照顧評論嗎? – bradgonesurfing
你的factory()方法是做什麼的? – mm8
@ mm8創建一個窗口。例如'CreateAndShowStaWindow(()=> new LoggerWindow())'。您可以返回任何窗口的子類。 – bradgonesurfing