This problem can be reproduced with the Embedding.UWP project on the https://github.com/xamarin/Xamarin.Forms/tree/embedding-uwp-multiwindow branch.
Launching a second UWP window and then attempting to embed a Forms page throws an unhandled exception. The exception occurs in Platform.cs, at
_container = new Canvas
{
Style = (Windows.UI.Xaml.Style)Windows.UI.Xaml.Application.Current.Resources["RootContainerStyle"]
};
StackTrace:
at System.Runtime.InteropServices.WindowsRuntime.IMap`2.Lookup(K key)
at System.Runtime.InteropServices.WindowsRuntime.MapToDictionaryAdapter.Lookup[K,V](IMap`2 _this, K key)
at System.Runtime.InteropServices.WindowsRuntime.MapToDictionaryAdapter.Indexer_Get[K,V](K key)
at Xamarin.Forms.Platform.UWP.Platform..ctor(Page page)
at Xamarin.Forms.Platform.UWP.WindowsPlatform..ctor(Page page)
at Xamarin.Forms.Platform.UWP.PageExtensions.ToFrameworkElement(VisualElement visualElement)
at Xamarin.Forms.Platform.UWP.PageExtensions.CreateFrameworkElement(ContentPage contentPage)
at Xamarin.Forms.Platform.UWP.FormsEmbeddedPageWrapper.OnNavigatedTo(NavigationEventArgs e)
Hi guys,
I'm the MSFT consultant working on this issue. Me and Edwin are working on a solution for this. Although our main focus is UWP, we are also planning to replicate this solution for Mac.
As we have limited knowledge over the Xamarin source-code and limited time also, we are working within some boundaries (maybe you could shed some light on our solution).
We forked the code and created this branch: https://github.com/edguer/Xamarin.Forms/tree/feature/openwindowuwp
In summary, we enabled multiples Xamarin.Forms.Application to run at the same time, and controlling the UWP RunAsync through the Application's WindowId property. As we included the WindowId property in the Element class, we can retrieve this information in every BindableObject and, therefore, execute a new BeginInvokeOnMainThread overload, which receives the WindowId as a parameter and execute the RunAsync for the correct Dispatcher related to that window.
Let me know if you need more info, maybe we could share some of our experiences.
Thanks!
Complementing the message above, we updated the LoadApplication method in WindowsBasePage to store the Dispatcher of the current application.
Upon window creating we are using the following code:
var windows = CoreApplication.Views;
var currentAV = ApplicationView.GetForCurrentView();
var newAV = CoreApplication.CreateNewView();
await newAV.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
async () =>
{
var newWindow = Window.Current;
var newAppView = ApplicationView.GetForCurrentView();
Windows.UI.Xaml.Controls.Frame frameContent = new Windows.UI.Xaml.Controls.Frame();
frameContent.Navigate(typeof(MainPageLite), "");
newWindow.Content = frameContent;
newWindow.Activate();
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(
newAppView.Id,
ViewSizePreference.UseMinimum,
currentAV.Id,
ViewSizePreference.UseMinimum);
});
MainPageLite is a native page, with LoadApplication, for each window there is a new Application of Xamarin.Forms.Core.
Another relevant aspect is: we changed the OnChildAdded on the class Element to populate the WindowId property in its own constructor.
Also, we changed the PropertyChanged method in the BindingExpression class to query for the correct Dispacther for executing the update in right UI Thread.
Update:
Today, we moved the WindowId property to BindableObject class, to populate that in Behavior class.
See PR #2432
Removing labels because this is active and in progress :)
Most helpful comment
Complementing the message above, we updated the LoadApplication method in WindowsBasePage to store the Dispatcher of the current application.
Upon window creating we are using the following code:
MainPageLite is a native page, with LoadApplication, for each window there is a new Application of Xamarin.Forms.Core.
Another relevant aspect is: we changed the OnChildAdded on the class Element to populate the WindowId property in its own constructor.
Also, we changed the PropertyChanged method in the BindingExpression class to query for the correct Dispacther for executing the update in right UI Thread.
Update:
Today, we moved the WindowId property to BindableObject class, to populate that in Behavior class.