-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Replace default MainThreadScheduler
on UAP
#2100
fix: Replace default MainThreadScheduler
on UAP
#2100
Conversation
@glennawatson I did give a multiple window scheduler the good ole' college try but after about a week of testing I do not think it's possible. See an attempt here: https://gist.github.com/hinterlandsupplyco/c8e0396f6d837fdc9cd2a5b00688b451
|
I'm going to get multiple reviewers on this one who have some uwp experience. So hang in there. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tried the new SingleWindowDispatcherScheduler
in several Universal Windows Platform applications, so far I confirm it works good without breaking anything, although those applications are all single window apps. This change seems reasonable to me, so I approve – at least this fixes the scheduler hijacking issue. Probably we should wait a bit longer to gather more opinions from UWP reviewers.
Thanks for this one @hinterlandsupplyco sure it will assist others. |
@glennawatson happy to contribute! :-) |
See reactiveui#2092, reactiveui#2032 for more info. This replaces the usage of `WaitForDispatcherScheduler` and `CoreDispatcherScheduler` with a scheduler that explicitly dispatches to the main app window regardless of how many windows are created by the application.
this fix does not work in the constellation WPF + WindowsXamlHost + UWP content. |
Hey @jasonwurzel if you can make a new issue even linking back to this one that would be great. |
Hello. I have tested new SingleWindowDispatcherScheduler and found bug. One of my view models has such code |
What kind of change does this PR introduce?
This replaces the usage of
WaitForDispatcherScheduler
andCoreDispatcherScheduler
with a schedulerSingleWindowDispatcherScheduler
that explicitly dispatches to the main app window regardless of how many windows are created by the application.What is the current behavior?
See #2092, #2034 for more info. Should also resolve or at least improve the situation in #1001. Every window created by the
CoreApplication
gets it's own shiny new UI thread andCoreDispatcher
. Example of this would be applications which use casting,ShareTarget
,ProjectionManager
or are just snazzy enough to have an app with multiple windows.Because
WaitForDispatcherScheduler
uses a factory to get an instance ofCoreDispatcherScheduler
andCoreDispatcherScheduler
usesWindow.Current
to obtain aCoreDispatcher
there are multiple ways forMainThreadScheduler
to be hijacked by a second window. For instance, if the thread being used by that window is returned to the thread pool (e.g. - by that window being closed or launching your main window from aShareTargetActivated
) then forever that[ThreadStatic]
instance ofMainThreadScheduler
will attempt to dispatch to an non-existent window. This will surface in thread marshaling exceptions which will very likely crash the user's application (or cause nasty UI issues like controls which no longer update).Of course, in these situations most devs will simply inject a scheduler into their view models for anything that used on a separate window. But this still won't block the hijacking because if code from the main window is ever executed on the thread separate window and then attempts to get an instance of
MainThreadScheduler
you could still have this problem. An example of this is code executing from the UI thread of window 2 updates an observable which is subscribed to on a view model or service being used in window 1. If in that code now in window 1 attempts toObserveOn(RxApp.MainThreadScheduler)
andMainThreadScheduler
does not have an instance for that thread (which it likely wouldn't since we aren't using it on our other window in this example) it will grab the wrong dispatcher because for that threadWindow.Current.Dispatcher
is not in fact null, but is the dispatcher for window 2.Since that is a very likely scenario in Rx, the problem should be solved in ReactiveUI.
What is the new behavior?
SingleWindowDispatcherScheduler
does not useCoreDispatcherScheduler
as its underlying scheduler, but does use code and patterns from that implementation.It also does not use
Window.Current
to find the correct dispatcher. Instead it usesCoreApplication.Views
to find the dispatcher. This has several advantages: 1) It is always available and you can get the correct dispatcher from any thread, 2) It is not possible to get the wrong dispatcher because your app's main window will always exist atCoreApplication.Views[0]
What might this PR break?
If for some reason a user was expressly relying on
RxApp.MainThreadScheduler
being of a specific type they will be discouraged from doing that ever again.Please check if the PR fulfills these requirements
Other information:
Unfortunately this code is not testable in a unit test, but then again neither are other platform schedulers (see
NSRunloopScheduler
). Since most of the actual dispatching code is taken fromCoreDispatcherScheduler
I think we are ok.A separate PR will be added to the website documentation to make it VERY clear that ReactiveUI supports one window UWP environments only out of the box and suggest appropriate workarounds for multiple windows.
Also tested that this will not cause a regression on fixes from c5b9462 (original issue: #1221)