Skip to content

Commit c3083b9

Browse files
authored
Support MainPage in the App constructor (#1419)
* Revert "Fix XamlApp to use CreateWindow for now" This reverts commit 929cb9b. * Ensure that the Forms.Init is called early enough * No slf for vscode * fix tests
1 parent c25eebe commit c3083b9

File tree

12 files changed

+117
-97
lines changed

12 files changed

+117
-97
lines changed

src/Compatibility/Core/src/AppHostBuilderExtensions.cs

Lines changed: 80 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -72,93 +72,125 @@ static IAppHostBuilder SetupDefaults(this IAppHostBuilder builder)
7272
{
7373
#if __ANDROID__
7474
events.AddAndroid(android => android
75-
.OnCreate((a, b) =>
75+
.OnApplicationCreating((app) =>
7676
{
77-
// This just gets Forms Compat bits setup with what it needs
78-
// to initialize the first view. MauiContext hasn't been initialized at this point
79-
// so we setup one that will look exactly the same just
80-
// to make legacy Forms bits happy
77+
// This is the initial Init to set up any system services registered by
78+
// Forms.Init(). This happens in the Application's OnCreate - before
79+
// any UI has appeared.
80+
// This creates a dummy MauiContext that wraps the Application.
81+
8182
var services = MauiApplication.Current.Services;
82-
MauiContext mauiContext = new MauiContext(services, a);
83-
ActivationState state = new ActivationState(mauiContext, b);
84-
Forms.Init(new ActivationState(mauiContext, b), new InitializationOptions() { Flags = InitializationFlags.SkipRenderers });
83+
var mauiContext = new MauiContext(services, app);
84+
var state = new ActivationState(mauiContext);
85+
Forms.Init(state, new InitializationOptions { Flags = InitializationFlags.SkipRenderers });
86+
8587
GraphicsPlatform.RegisterGlobalService(NativeGraphicsService.Instance);
8688
})
87-
.OnPostCreate((_, b) =>
89+
.OnCreate((activity, bundle) =>
90+
{
91+
// This is the Init that sets up the first context from the activity.
92+
// There is still no official MauiContext since that happens just after this.
93+
94+
var services = MauiApplication.Current.Services;
95+
var mauiContext = new MauiContext(services, activity);
96+
var state = new ActivationState(mauiContext, bundle);
97+
Forms.Init(state, new InitializationOptions { Flags = InitializationFlags.SkipRenderers });
98+
})
99+
.OnPostCreate((activity, bundle) =>
88100
{
89-
// This calls Init again so that the MauiContext that's part of
90-
// Forms.Init matches the rest of the maui application
91-
var mauiApp = MauiApplication.Current.Application;
92-
if (mauiApp.Windows.Count > 0)
101+
// This is the final Init that ensures the Forms type is using the same
102+
// MauiContext that is part of the rest of the maui application.
103+
104+
var windows = Application.Current?.Windows;
105+
if (windows?.Count > 0)
93106
{
94-
var window = mauiApp.Windows[0];
95-
var mauiContext = window.Handler?.MauiContext ?? window.View.Handler?.MauiContext;
107+
var window = windows[0];
108+
var mauiContext =
109+
window.Handler?.MauiContext ??
110+
window.Page?.Handler?.MauiContext;
96111

97112
if (mauiContext != null)
98113
{
99-
Forms.Init(new ActivationState(mauiContext, b));
114+
var state = new ActivationState(mauiContext, bundle);
115+
Forms.Init(state);
100116
}
101117
}
102118
}));
103119
#elif __IOS__
104-
events.AddiOS(iOS =>
105-
{
106-
iOS.WillFinishLaunching((x, y) =>
120+
events.AddiOS(iOS => iOS
121+
.WillFinishLaunching((app, options) =>
107122
{
108-
MauiContext mauiContext = new MauiContext(MauiUIApplicationDelegate.Current.Services, new UIKit.UIWindow());
109-
Forms.Init(new ActivationState(mauiContext), new InitializationOptions() { Flags = InitializationFlags.SkipRenderers });
110-
return true;
111-
});
123+
// This is the initial Init to set up any system services registered by
124+
// Forms.Init(). This happens before any UI has appeared.
125+
// This creates a dummy MauiContext.
112126

113-
iOS.FinishedLaunching((x,y) =>
127+
var services = MauiUIApplicationDelegate.Current.Services;
128+
var mauiContext = new MauiContext(services);
129+
var state = new ActivationState(mauiContext);
130+
Forms.Init(state, new InitializationOptions { Flags = InitializationFlags.SkipRenderers });
131+
return true;
132+
})
133+
.FinishedLaunching((app, options) =>
114134
{
115-
// This calls Init again so that the MauiContext that's part of
116-
// Forms.Init matches the rest of the maui application
117-
var mauiApp = MauiUIApplicationDelegate.Current.Application;
135+
// This is the final Init that ensures the Forms type is using the same
136+
// MauiContext that is part of the rest of the maui application.
118137

119-
if (mauiApp.Windows.Count > 0)
138+
var windows = Application.Current?.Windows;
139+
if (windows?.Count > 0)
120140
{
121-
var window = mauiApp.Windows[0];
122-
var mauiContext = window.Handler?.MauiContext ?? window.View.Handler?.MauiContext;
141+
var window = windows[0];
142+
var mauiContext =
143+
window.Handler?.MauiContext ??
144+
window.Page?.Handler?.MauiContext;
123145

124146
if (mauiContext != null)
125147
{
126-
Forms.Init(new ActivationState(mauiContext));
148+
var state = new ActivationState(mauiContext);
149+
Forms.Init(state);
127150
}
128151
}
129-
152+
130153
GraphicsPlatform.RegisterGlobalService(NativeGraphicsService.Instance);
131154

132155
return true;
133-
});
134-
});
156+
}));
135157
#elif WINDOWS
136158
events.AddWindows(windows => windows
137-
.OnLaunching((_, args) =>
159+
.OnLaunching((app, args) =>
138160
{
139-
// We need to call Forms.Init so the Window and Root Page can new up successfully
140-
// The dispatcher that's inside of Forms.Init needs to be setup before the initial
141-
// window and root page start creating
161+
// This is the initial Init to set up any system services registered by
162+
// Forms.Init(). This happens before any UI has appeared.
163+
// This creates a dummy MauiContext.
164+
// We need to call this so the Window and Root Page can new up successfully
165+
// The dispatcher that's inside of Forms.Init needs to be setup before the initial
166+
// window and root page start creating.
142167
// Inside OnLaunched we grab the MauiContext that's on the window so we can have the correct
143168
// MauiContext inside Forms
144-
MauiContext mauiContext = new MauiContext(MauiWinUIApplication.Current.Services, new UI.Xaml.Window());
145-
ActivationState state = new ActivationState(mauiContext, args);
169+
170+
var services = MauiWinUIApplication.Current.Services;
171+
var mauiContext = new MauiContext(services);
172+
var state = new ActivationState(mauiContext, args);
146173
Forms.Init(state, new InitializationOptions() { Flags = InitializationFlags.SkipRenderers });
174+
147175
GraphicsPlatform.RegisterGlobalService(W2DGraphicsService.Instance);
148176
})
149-
.OnLaunched((_, args) =>
177+
.OnLaunched((app, args) =>
150178
{
151-
// This calls Init again so that the MauiContext that's part of
152-
// Forms.Init matches the rest of the maui application
153-
var mauiApp = MauiWinUIApplication.Current.Application;
154-
if (mauiApp.Windows.Count > 0)
179+
// This is the final Init that ensures the Forms type is using the same
180+
// MauiContext that is part of the rest of the maui application.
181+
182+
var windows = Application.Current?.Windows;
183+
if (windows?.Count > 0)
155184
{
156-
var window = mauiApp.Windows[0];
157-
var mauiContext = window.Handler?.MauiContext ?? window.View.Handler?.MauiContext;
185+
var window = windows[0];
186+
var mauiContext =
187+
window.Handler?.MauiContext ??
188+
window.Page?.Handler?.MauiContext;
158189

159190
if (mauiContext != null)
160191
{
161-
Forms.Init(new ActivationState(mauiContext, args));
192+
var state = new ActivationState(mauiContext, args);
193+
Forms.Init(state);
162194
}
163195
}
164196
}));

src/Controls/samples/Controls.Sample/XamlApp.xaml.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ public XamlApp(IServiceProvider services, ITextService textService)
1717

1818
Debug.WriteLine($"The .NET Purple color is {Resources["DotNetPurple"]}");
1919
Debug.WriteLine($"The injected text service had a message: '{textService.GetText()}'");
20-
}
2120

22-
protected override Window CreateWindow(IActivationState activationState)
23-
{
24-
return new Window(Services.GetRequiredService<Page>());
21+
MainPage = Services.GetRequiredService<Page>();
2522
}
2623

2724
public IServiceProvider Services { get; }

src/Core/src/LifecycleEvents/Android/AndroidLifecycleExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ public LifecycleBuilder(ILifecycleBuilder builder)
2222
_builder = builder;
2323
}
2424

25-
public void AddEvent(string eventName, Delegate action) =>
25+
public void AddEvent<TDelegate>(string eventName, TDelegate action)
26+
where TDelegate : Delegate
27+
{
2628
_builder.AddEvent(eventName, action);
29+
}
2730
}
2831
}
2932
}

src/Core/src/LifecycleEvents/ILifecycleBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ namespace Microsoft.Maui.LifecycleEvents
44
{
55
public interface ILifecycleBuilder
66
{
7-
void AddEvent(string eventName, Delegate action);
7+
void AddEvent<TDelegate>(string eventName, TDelegate action)
8+
where TDelegate : Delegate;
89
}
910
}

src/Core/src/LifecycleEvents/LifecycleEventService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ public class LifecycleEventService : ILifecycleEventService
88
{
99
readonly Dictionary<string, List<Delegate>> _mapper = new Dictionary<string, List<Delegate>>();
1010

11-
public void AddEvent(string eventName, Delegate action)
11+
public void AddEvent<TDelegate>(string eventName, TDelegate action)
12+
where TDelegate : Delegate
1213
{
1314
if (!_mapper.TryGetValue(eventName, out var delegates) && delegates == null)
1415
_mapper[eventName] = delegates = new List<Delegate>();

src/Core/src/LifecycleEvents/Windows/WindowsLifecycleExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ public LifecycleBuilder(ILifecycleBuilder builder)
2222
_builder = builder;
2323
}
2424

25-
public void AddEvent(string eventName, Delegate action) =>
25+
public void AddEvent<TDelegate>(string eventName, TDelegate action)
26+
where TDelegate : Delegate
27+
{
2628
_builder.AddEvent(eventName, action);
29+
}
2730
}
2831
}
2932
}

src/Core/src/LifecycleEvents/iOS/iOSLifecycleExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ public LifecycleBuilder(ILifecycleBuilder builder)
2222
_builder = builder;
2323
}
2424

25-
public void AddEvent(string eventName, Delegate action) =>
25+
public void AddEvent<TDelegate>(string eventName, TDelegate action)
26+
where TDelegate : Delegate
27+
{
2628
_builder.AddEvent(eventName, action);
29+
}
2730
}
2831
}
2932
}

src/Core/src/Platform/Android/MauiAppCompatActivity.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,17 @@ protected override void OnCreate(Bundle? savedInstanceState)
4141
if (mauiApp == null)
4242
throw new InvalidOperationException($"The {nameof(IServiceProvider)} instance was not found.");
4343

44-
MauiContext mauiContext;
45-
IWindow window;
44+
var mauiContext = new MauiContext(services, this);
4645

4746
// TODO Fix once we have multiple windows
47+
IWindow window;
4848
if (mauiApp.Windows.Count > 0)
4949
{
5050
window = mauiApp.Windows[0];
51-
mauiContext = new MauiContext(services, this);
5251
}
5352
else
5453
{
55-
mauiContext = new MauiContext(services, this);
56-
ActivationState state = new ActivationState(mauiContext, savedInstanceState);
54+
var state = new ActivationState(mauiContext, savedInstanceState);
5755
window = mauiApp.CreateWindow(state);
5856
}
5957

src/Core/src/Platform/MauiContext.Android.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
42
using Android.Content;
5-
using Microsoft.Extensions.DependencyInjection;
6-
73

84
namespace Microsoft.Maui
95
{
106
public partial class MauiContext
117
{
128
readonly WeakReference<Context>? _context;
13-
public MauiContext(IServiceProvider services, Context context) : this(services)
9+
10+
public MauiContext(IServiceProvider services, Context context)
11+
: this(services)
1412
{
1513
_context = new WeakReference<Context>(context ?? throw new ArgumentNullException(nameof(context)));
1614
}
1715

18-
public MauiContext(Context context) : this()
16+
public MauiContext(Context context)
17+
: this()
1918
{
19+
_context = new WeakReference<Context>(context ?? throw new ArgumentNullException(nameof(context)));
2020
}
2121

2222
public Context? Context
@@ -26,13 +26,7 @@ public Context? Context
2626
if (_context == null)
2727
return null;
2828

29-
Context? context;
30-
if (_context.TryGetTarget(out context))
31-
{
32-
return context;
33-
}
34-
35-
return null;
29+
return _context.TryGetTarget(out Context? context) ? context : null;
3630
}
3731
}
3832
}
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
42

53
namespace Microsoft.Maui
64
{
75
public partial class MauiContext
86
{
9-
public MauiContext(IServiceProvider services, UI.Xaml.Window window) : this(services)
7+
public MauiContext(IServiceProvider services, UI.Xaml.Window window)
8+
: this(services)
109
{
1110
Window = window ?? throw new ArgumentNullException(nameof(window));
1211
}
1312

14-
public UI.Xaml.Window? Window
15-
{
16-
get;
17-
private set;
18-
}
13+
public UI.Xaml.Window? Window { get; private set; }
1914
}
20-
}
15+
}

0 commit comments

Comments
 (0)