Skip to content

Commit 8966b71

Browse files
[XSG] support full-page XHR (#32253)
* [XSG] support full-page XHR if XHR provides a replaced xaml, fallback to runtime inflation * [XSG] add test, fix code
1 parent bd3ab73 commit 8966b71

File tree

12 files changed

+308
-4
lines changed

12 files changed

+308
-4
lines changed

src/Controls/src/SourceGen/CodeBehindCodeWriter.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,16 @@ public static string GenerateXamlCodeBehind(XamlProjectItemForCB? xamlItem, Comp
149149
InitComp("InitializeComponent");
150150
else if ((xamlInflators & XamlInflator.XamlC) == XamlInflator.XamlC)
151151
InitComp("InitializeComponent");
152-
else if ((xamlInflators & XamlInflator.SourceGen) == XamlInflator.SourceGen)
152+
else if ((xamlInflators & XamlInflator.SourceGen) == XamlInflator.SourceGen) {
153153
InitComp("InitializeComponent", partialsignature: true);
154+
//generate InitCompRuntime for HotReload fallback
155+
if (projItem.EnableDiagnostics)
156+
InitComp("InitializeComponentRuntime");
157+
}
154158
}
155159
else
156160
{
157-
if ((xamlInflators & XamlInflator.Runtime) == XamlInflator.Runtime)
161+
if ((xamlInflators & XamlInflator.Runtime) == XamlInflator.Runtime || projItem.EnableDiagnostics)
158162
InitComp("InitializeComponentRuntime");
159163
if ((xamlInflators & XamlInflator.XamlC) == XamlInflator.XamlC)
160164
InitComp("InitializeComponentXamlC", empty: true);

src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,37 @@ PrePost newblock() =>
9393
var sgcontext = new SourceGenContext(codeWriter, compilation, sourceProductionContext, xmlnsCache, typeCache, rootType!, baseType, xamlItem.ProjectItem);
9494
using (newblock())
9595
{
96+
if (xamlItem.ProjectItem.EnableDiagnostics)
97+
{
98+
codeWriter.WriteLine(
99+
$$"""
100+
// Fallback to Runtime inflation if the page was updated by HotReload
101+
static string? getPathForType(global::System.Type type)
102+
{
103+
var assembly = type.Assembly;
104+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
105+
{
106+
if (xria.Type == type)
107+
return xria.Path;
108+
}
109+
return null;
110+
}
111+
112+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
113+
{
114+
AssemblyName = typeof({{rootType.ToFQDisplayString()}}).Assembly.GetName(),
115+
ResourcePath = getPathForType(typeof({{rootType.ToFQDisplayString()}})),
116+
Instance = this,
117+
});
118+
119+
if (rlr?.ResourceContent != null)
120+
{
121+
this.InitializeComponentRuntime();
122+
return;
123+
}
124+
125+
""");
126+
}
96127
Visit(root, sgcontext);
97128

98129
foreach (var localMethod in sgcontext.LocalMethods)

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/BasicCase.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,31 @@ internal partial class TestPage
6060
{
6161
private partial void InitializeComponent()
6262
{
63+
// Fallback to Runtime inflation if the page was updated by HotReload
64+
static string? getPathForType(global::System.Type type)
65+
{
66+
var assembly = type.Assembly;
67+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
68+
{
69+
if (xria.Type == type)
70+
return xria.Path;
71+
}
72+
return null;
73+
}
74+
75+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
76+
{
77+
AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(),
78+
ResourcePath = getPathForType(typeof(global::Test.TestPage)),
79+
Instance = this,
80+
});
81+
82+
if (rlr?.ResourceContent != null)
83+
{
84+
this.InitializeComponentRuntime();
85+
return;
86+
}
87+
6388
var button = new global::Microsoft.Maui.Controls.Button();
6489
global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(button!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 7, 4);
6590
var __root = this;

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/CompiledBindings.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,31 @@ public partial class TestPage
7171
{
7272
private partial void InitializeComponent()
7373
{
74+
// Fallback to Runtime inflation if the page was updated by HotReload
75+
static string? getPathForType(global::System.Type type)
76+
{
77+
var assembly = type.Assembly;
78+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
79+
{
80+
if (xria.Type == type)
81+
return xria.Path;
82+
}
83+
return null;
84+
}
85+
86+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
87+
{
88+
AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(),
89+
ResourcePath = getPathForType(typeof(global::Test.TestPage)),
90+
Instance = this,
91+
});
92+
93+
if (rlr?.ResourceContent != null)
94+
{
95+
this.InitializeComponentRuntime();
96+
return;
97+
}
98+
7499
var bindingExtension = new global::Microsoft.Maui.Controls.Xaml.BindingExtension();
75100
global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(bindingExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 5);
76101
var __root = this;

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/ResourceDictionary.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,31 @@ public partial class __TypeDBD64C1C77CDA760
3636
{
3737
private partial void InitializeComponent()
3838
{
39+
// Fallback to Runtime inflation if the page was updated by HotReload
40+
static string? getPathForType(global::System.Type type)
41+
{
42+
var assembly = type.Assembly;
43+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
44+
{
45+
if (xria.Type == type)
46+
return xria.Path;
47+
}
48+
return null;
49+
}
50+
51+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
52+
{
53+
AssemblyName = typeof(global::__XamlGeneratedCode__.__TypeDBD64C1C77CDA760).Assembly.GetName(),
54+
ResourcePath = getPathForType(typeof(global::__XamlGeneratedCode__.__TypeDBD64C1C77CDA760)),
55+
Instance = this,
56+
});
57+
58+
if (rlr?.ResourceContent != null)
59+
{
60+
this.InitializeComponentRuntime();
61+
return;
62+
}
63+
3964
var color = new global::Microsoft.Maui.Graphics.Color(1f, 0.29411766f, 0.078431375f, 1f) /* #FF4B14 */;
4065
global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(color!, new global::System.Uri(@"Styles.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 4);
4166
var __root = this;

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/SetBinding.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,31 @@ public partial class TestPage
5757
{
5858
private partial void InitializeComponent()
5959
{
60+
// Fallback to Runtime inflation if the page was updated by HotReload
61+
static string? getPathForType(global::System.Type type)
62+
{
63+
var assembly = type.Assembly;
64+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
65+
{
66+
if (xria.Type == type)
67+
return xria.Path;
68+
}
69+
return null;
70+
}
71+
72+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
73+
{
74+
AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(),
75+
ResourcePath = getPathForType(typeof(global::Test.TestPage)),
76+
Instance = this,
77+
});
78+
79+
if (rlr?.ResourceContent != null)
80+
{
81+
this.InitializeComponentRuntime();
82+
return;
83+
}
84+
6085
var bindingExtension = new global::Microsoft.Maui.Controls.Xaml.BindingExtension();
6186
global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(bindingExtension!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 6, 5);
6287
var __root = this;

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/SimplifyOnPlatform.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,31 @@ public partial class TestPage
6363
{
6464
private partial void InitializeComponent()
6565
{
66+
// Fallback to Runtime inflation if the page was updated by HotReload
67+
static string? getPathForType(global::System.Type type)
68+
{
69+
var assembly = type.Assembly;
70+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
71+
{
72+
if (xria.Type == type)
73+
return xria.Path;
74+
}
75+
return null;
76+
}
77+
78+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
79+
{
80+
AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(),
81+
ResourcePath = getPathForType(typeof(global::Test.TestPage)),
82+
Instance = this,
83+
});
84+
85+
if (rlr?.ResourceContent != null)
86+
{
87+
this.InitializeComponentRuntime();
88+
return;
89+
}
90+
6691
var setter = new global::Microsoft.Maui.Controls.Setter();
6792
global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(setter!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 8, 14);
6893
var setter1 = new global::Microsoft.Maui.Controls.Setter();

src/Controls/tests/SourceGen.UnitTests/InitializeComponent/WarningIgnore.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,31 @@ public partial class TestPage
6161
{
6262
private partial void InitializeComponent()
6363
{
64+
// Fallback to Runtime inflation if the page was updated by HotReload
65+
static string? getPathForType(global::System.Type type)
66+
{
67+
var assembly = type.Assembly;
68+
foreach (var xria in global::System.Reflection.CustomAttributeExtensions.GetCustomAttributes<global::Microsoft.Maui.Controls.Xaml.XamlResourceIdAttribute>(assembly))
69+
{
70+
if (xria.Type == type)
71+
return xria.Path;
72+
}
73+
return null;
74+
}
75+
76+
var rlr = global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceProvider2?.Invoke(new global::Microsoft.Maui.Controls.Internals.ResourceLoader.ResourceLoadingQuery
77+
{
78+
AssemblyName = typeof(global::Test.TestPage).Assembly.GetName(),
79+
ResourcePath = getPathForType(typeof(global::Test.TestPage)),
80+
Instance = this,
81+
});
82+
83+
if (rlr?.ResourceContent != null)
84+
{
85+
this.InitializeComponentRuntime();
86+
return;
87+
}
88+
6489
var button = new global::Microsoft.Maui.Controls.Button();
6590
global::Microsoft.Maui.VisualDiagnostics.RegisterSourceInfo(button!, new global::System.Uri(@"Test.xaml;assembly=SourceGeneratorDriver.Generated", global::System.UriKind.Relative), 7, 4);
6691
var __root = this;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.HotReload"
5+
Title="HotReload">
6+
<VerticalStackLayout>
7+
<Label
8+
x:Name="label0"
9+
Text="Welcome to .NET MAUI!"
10+
VerticalOptions="Center"
11+
BackgroundColor="Lime"
12+
HorizontalOptions="Center" />
13+
</VerticalStackLayout>
14+
</ContentPage>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using Microsoft.Maui.ApplicationModel;
2+
using Microsoft.Maui.Controls.Core.UnitTests;
3+
using Microsoft.Maui.Dispatching;
4+
using Microsoft.Maui.Graphics;
5+
using Microsoft.Maui.UnitTests;
6+
using NUnit.Framework;
7+
8+
namespace Microsoft.Maui.Controls.Xaml.UnitTests;
9+
10+
public partial class HotReload : ContentPage
11+
{
12+
public HotReload() => InitializeComponent();
13+
14+
[TestFixture]
15+
class Tests
16+
{
17+
[SetUp]
18+
public void Setup()
19+
{
20+
Application.SetCurrentApplication(new MockApplication());
21+
DispatcherProvider.SetCurrent(new DispatcherProviderStub());
22+
}
23+
24+
[TearDown]
25+
public void TearDown()
26+
{
27+
AppInfo.SetCurrent(null);
28+
Controls.Internals.ResourceLoader.ResourceProvider2 = null;
29+
Controls.Internals.ResourceLoader.ExceptionHandler2 = null;
30+
}
31+
32+
#if DEBUG
33+
[Test]
34+
public void HotReloadWorks([Values(XamlInflator.Runtime, XamlInflator.SourceGen)] XamlInflator inflator)
35+
{
36+
var page = new HotReload(inflator);
37+
Assert.That(page.label0.BackgroundColor, Is.EqualTo(Colors.Lime));
38+
39+
var updatedXaml =
40+
"""
41+
<?xml version="1.0" encoding="utf-8" ?>
42+
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
43+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
44+
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.HotReload"
45+
Title="HotReload">
46+
<VerticalStackLayout>
47+
<Label
48+
x:Name="label0"
49+
Text="Welcome to .NET MAUI!"
50+
VerticalOptions="Center"
51+
BackgroundColor="HotPink"
52+
HorizontalOptions="Center" />
53+
</VerticalStackLayout>
54+
</ContentPage>
55+
""";
56+
57+
Controls.Internals.ResourceLoader.ResourceProvider2 = (query) =>
58+
{
59+
if (query.ResourcePath.EndsWith("HotReload.xaml"))
60+
{
61+
return new Controls.Internals.ResourceLoader.ResourceLoadingResponse
62+
{
63+
ResourceContent = updatedXaml,
64+
UseDesignProperties = false
65+
};
66+
}
67+
return null;
68+
};
69+
70+
page = new HotReload(inflator);
71+
72+
Assert.That(page.label0.BackgroundColor, Is.EqualTo(Colors.HotPink));
73+
74+
}
75+
#endif
76+
}
77+
}

0 commit comments

Comments
 (0)