Skip to content

Commit 3143ba3

Browse files
mattleibowPureWeen
andauthored
Add back support for using MainPage instead of CreateWindow (#1262)
* WIP to get MainPage working * - add additional init inside OnCreate * Revert things and update templates * Make this better * can skip that * revert that Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
1 parent 8fe0cf3 commit 3143ba3

File tree

13 files changed

+249
-79
lines changed

13 files changed

+249
-79
lines changed

src/Compatibility/ControlGallery/src/Core/App.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,11 @@ public App()
3535

3636
//TestMainPageSwitches();
3737

38-
if (Device.RuntimePlatform != Device.iOS)
39-
SetMainPage(new ImageSourcesGallery());
40-
}
38+
SetMainPage(CreateDefaultMainPage());
4139

42-
protected override IWindow CreateWindow(IActivationState activationState)
43-
{
44-
return new Window(CreateDefaultMainPage());
40+
//TestMainPageSwitches();
41+
42+
//SetMainPage(new ImageSourcesGallery());
4543
}
4644

4745
protected override void OnStart()

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@ 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+
21+
MainPage = Services.GetRequiredService<Page>();
2022
}
2123

2224
public IServiceProvider Services { get; }
23-
24-
protected override IWindow CreateWindow(IActivationState activationState)
25-
{
26-
return Services.GetRequiredService<IWindow>();
27-
}
2825
}
2926
}

src/Controls/src/Core/Application.cs

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -63,82 +63,60 @@ public IAppLinks AppLinks
6363

6464
public static Application Current { get; set; }
6565

66-
// TODO MAUI. What should this be?
6766
public Page MainPage
6867
{
6968
get
7069
{
7170
if (Windows.Count == 0)
7271
return null;
7372

74-
return Windows[0].View as Page;
73+
return Windows[0].Page;
7574
}
7675
set
7776
{
7877
if (value == null)
79-
throw new ArgumentNullException("value");
78+
throw new ArgumentNullException(nameof(value));
8079

8180
if (MainPage == value)
8281
return;
8382

83+
OnPropertyChanging();
84+
85+
var previousPage = MainPage;
86+
87+
if (previousPage != null)
88+
previousPage.Parent = null;
89+
8490
if (Windows.Count == 0)
8591
{
86-
OnPropertyChanging();
92+
// there are no windows, so add a new window
93+
8794
AddWindow(new Window(value));
88-
OnPropertyChanged();
8995
}
9096
else
9197
{
92-
var mainPage = MainPage;
93-
94-
if (mainPage == value)
95-
return;
96-
97-
OnPropertyChanging();
98-
if (mainPage != null)
99-
mainPage.Parent = null;
100-
101-
Windows[0].View = (IView)value;
98+
// find the best window and replace the page
99+
100+
var theWindow = Windows[0];
101+
foreach (var window in Windows)
102+
{
103+
if (window.Page == previousPage)
104+
{
105+
theWindow = window;
106+
break;
107+
}
108+
}
109+
110+
theWindow.Page = value;
111+
}
102112

103-
if (mainPage != null)
104-
mainPage.NavigationProxy.Inner = NavigationProxy;
113+
if (previousPage != null)
114+
previousPage.NavigationProxy.Inner = NavigationProxy;
105115

106-
OnPropertyChanged();
107-
}
116+
OnPropertyChanged();
108117
}
109118
}
110119

111-
//public Page MainPage
112-
//{
113-
// get { return _mainPage; }
114-
// set
115-
// {
116-
// if (value == null)
117-
// throw new ArgumentNullException("value");
118-
119-
// if (_mainPage == value)
120-
// return;
121-
122-
// OnPropertyChanging();
123-
// if (_mainPage != null)
124-
// {
125-
// InternalChildren.Remove(_mainPage);
126-
// _mainPage.Parent = null;
127-
// }
128-
129-
// _mainPage = value;
130-
131-
// if (_mainPage != null)
132-
// {
133-
// _mainPage.Parent = this;
134-
// _mainPage.NavigationProxy.Inner = NavigationProxy;
135-
// InternalChildren.Add(_mainPage);
136-
// }
137-
138-
// OnPropertyChanged();
139-
// }
140-
//}
141-
142120
public IDictionary<string, object> Properties
143121
{
144122
get

src/Controls/src/Core/HandlerImpl/Application.Impl.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@ namespace Microsoft.Maui.Controls
55
{
66
public partial class Application : IApplication
77
{
8-
List<IWindow> _windows = new List<IWindow>();
9-
public IReadOnlyList<IWindow> Windows => _windows.AsReadOnly();
8+
readonly List<Window> _windows = new();
9+
10+
IReadOnlyList<IWindow> IApplication.Windows => Windows;
11+
12+
public IReadOnlyList<Window> Windows => _windows.AsReadOnly();
1013

1114
IWindow IApplication.CreateWindow(IActivationState activationState)
1215
{
13-
IWindow window = CreateWindow(activationState);
16+
var window = CreateWindow(activationState);
1417

15-
AddWindow(window);
18+
if (!_windows.Contains(window))
19+
AddWindow(window);
1620

1721
return window;
1822
}
1923

20-
void AddWindow(IWindow window)
24+
void AddWindow(Window window)
2125
{
2226
_windows.Add(window);
2327

@@ -32,9 +36,12 @@ void AddWindow(IWindow window)
3236
ne.NavigationProxy.Inner = NavigationProxy;
3337
}
3438

35-
protected virtual IWindow CreateWindow(IActivationState activationState)
39+
protected virtual Window CreateWindow(IActivationState activationState)
3640
{
37-
throw new NotImplementedException();
41+
if (Windows.Count > 0)
42+
return Windows[0];
43+
44+
throw new NotImplementedException($"Either set {nameof(MainPage)} or override {nameof(Application.CreateWindow)}.");
3845
}
3946
}
4047
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
using System;
2+
using NUnit.Framework;
3+
4+
namespace Microsoft.Maui.Controls.Core.UnitTests
5+
{
6+
[TestFixture]
7+
public class ApplicationTests : BaseTestFixture
8+
{
9+
[Test]
10+
public void NewApplicationHasNoWindowsNorPage()
11+
{
12+
var app = new Application();
13+
14+
Assert.Null(app.MainPage);
15+
Assert.IsEmpty(app.Windows);
16+
}
17+
18+
[Test]
19+
public void SettingMainPageSetsMainPageAndWindow()
20+
{
21+
var app = new Application();
22+
var page = new ContentPage();
23+
24+
app.MainPage = page;
25+
26+
Assert.AreEqual(page, app.MainPage);
27+
Assert.AreEqual(1, app.Windows.Count);
28+
Assert.AreEqual(page, app.Windows[0].Page);
29+
}
30+
31+
[Test]
32+
public void CreateWindowUsesMainPage()
33+
{
34+
var app = new Application();
35+
var iapp = app as IApplication;
36+
var page = new ContentPage();
37+
38+
app.MainPage = page;
39+
40+
var window = iapp.CreateWindow(null);
41+
42+
Assert.AreEqual(page, app.MainPage);
43+
Assert.IsNotEmpty(app.Windows);
44+
Assert.AreEqual(1, app.Windows.Count);
45+
Assert.AreEqual(window, app.Windows[0]);
46+
Assert.AreEqual(page, app.Windows[0].Page);
47+
}
48+
49+
[Test]
50+
public void SettingMainPageUpdatesWindow()
51+
{
52+
var app = new Application();
53+
var iapp = app as IApplication;
54+
var page = new ContentPage();
55+
56+
app.MainPage = page;
57+
var window = iapp.CreateWindow(null);
58+
59+
var page2 = new ContentPage();
60+
app.MainPage = page2;
61+
62+
Assert.AreEqual(page2, app.MainPage);
63+
Assert.IsNotEmpty(app.Windows);
64+
Assert.AreEqual(1, app.Windows.Count);
65+
Assert.AreEqual(window, app.Windows[0]);
66+
Assert.AreEqual(page2, app.Windows[0].Page);
67+
}
68+
69+
[Test]
70+
public void NotSettingMainPageThrows()
71+
{
72+
var app = new Application();
73+
var iapp = app as IApplication;
74+
75+
Assert.Throws<NotImplementedException>(() => iapp.CreateWindow(null));
76+
}
77+
78+
[Test]
79+
public void CanUseExistingWindow()
80+
{
81+
var window = new Window();
82+
83+
var app = new StubApp { MainWindow = window };
84+
var iapp = app as IApplication;
85+
86+
var win = iapp.CreateWindow(null);
87+
88+
Assert.AreEqual(window, win);
89+
Assert.Null(app.MainPage);
90+
}
91+
92+
[Test]
93+
public void CanUseExistingWindowWithPage()
94+
{
95+
var window = new Window { Page = new ContentPage() };
96+
97+
var app = new StubApp { MainWindow = window };
98+
var iapp = app as IApplication;
99+
100+
var win = iapp.CreateWindow(null);
101+
102+
Assert.AreEqual(window, win);
103+
Assert.AreEqual(window.Page, app.MainPage);
104+
}
105+
106+
[Test]
107+
public void SettingMainPageOverwritesExistingPage()
108+
{
109+
var window = new Window { Page = new ContentPage() };
110+
111+
var app = new StubApp { MainWindow = window };
112+
var iapp = app as IApplication;
113+
114+
var win = iapp.CreateWindow(null);
115+
116+
var page2 = new ContentPage();
117+
app.MainPage = page2;
118+
119+
Assert.AreEqual(window, win);
120+
Assert.AreEqual(page2, app.MainPage);
121+
Assert.AreEqual(window.Page, app.MainPage);
122+
}
123+
124+
[Test]
125+
public void SettingWindowPageOverwritesMainPage()
126+
{
127+
var window = new Window { Page = new ContentPage() };
128+
129+
var app = new StubApp { MainWindow = window };
130+
var iapp = app as IApplication;
131+
132+
var win = iapp.CreateWindow(null);
133+
134+
var page2 = new ContentPage();
135+
window.Page = page2;
136+
137+
Assert.AreEqual(window, win);
138+
Assert.AreEqual(page2, app.MainPage);
139+
Assert.AreEqual(window.Page, app.MainPage);
140+
}
141+
142+
class StubApp : Application
143+
{
144+
public Window MainWindow { get; set; }
145+
146+
protected override Window CreateWindow(IActivationState activationState)
147+
{
148+
return MainWindow;
149+
}
150+
}
151+
}
152+
}

src/Controls/tests/Core.UnitTests/WindowsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public class TestApp : Application
7272
public TestWindow CreateWindow() =>
7373
(TestWindow)(this as IApplication).CreateWindow(null);
7474

75-
protected override IWindow CreateWindow(IActivationState activationState)
75+
protected override Window CreateWindow(IActivationState activationState)
7676
{
7777
return new TestWindow(new ContentPage());
7878
}

src/Core/src/LifecycleEvents/Android/AndroidLifecycle.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ namespace Microsoft.Maui.LifecycleEvents
88
{
99
public static class AndroidLifecycle
1010
{
11+
// Events called by the Application
12+
public delegate void OnApplicationCreating(Application application);
13+
public delegate void OnApplicationCreate(Application application);
14+
public delegate void OnApplicationLowMemory(Application application);
15+
public delegate void OnApplicationTrimMemory(Application application, TrimMemory level);
16+
public delegate void OnApplicationConfigurationChanged(Application application, Configuration newConfig);
17+
1118
// Events called by the ActivityLifecycleCallbacks
1219
public delegate void OnCreate(Activity activity, Bundle? savedInstanceState);
1320
public delegate void OnStart(Activity activity);

src/Core/src/LifecycleEvents/Android/AndroidLifecycleBuilderExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
{
33
public static class AndroidLifecycleBuilderExtensions
44
{
5+
public static IAndroidLifecycleBuilder OnApplicationCreating(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnApplicationCreating del) => lifecycle.OnEvent(del);
6+
public static IAndroidLifecycleBuilder OnApplicationCreate(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnApplicationCreate del) => lifecycle.OnEvent(del);
7+
public static IAndroidLifecycleBuilder OnApplicationLowMemory(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnApplicationLowMemory del) => lifecycle.OnEvent(del);
8+
public static IAndroidLifecycleBuilder OnApplicationTrimMemory(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnApplicationTrimMemory del) => lifecycle.OnEvent(del);
9+
public static IAndroidLifecycleBuilder OnApplicationConfigurationChanged(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnApplicationConfigurationChanged del) => lifecycle.OnEvent(del);
10+
511
public static IAndroidLifecycleBuilder OnActivityResult(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnActivityResult del) => lifecycle.OnEvent(del);
612
public static IAndroidLifecycleBuilder OnBackPressed(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnBackPressed del) => lifecycle.OnEvent(del);
713
public static IAndroidLifecycleBuilder OnConfigurationChanged(this IAndroidLifecycleBuilder lifecycle, AndroidLifecycle.OnConfigurationChanged del) => lifecycle.OnEvent(del);

0 commit comments

Comments
 (0)