-
Notifications
You must be signed in to change notification settings - Fork 1.8k
XAML xmlns simplifications #29579
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
base: net10.0
Are you sure you want to change the base?
XAML xmlns simplifications #29579
Conversation
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.
Pull Request Overview
Adds a new global XAML xmlns, enables implicit xmlns declarations via a preview feature flag, protects built-in xmlns entries, and updates related source generators and metadata.
- Introduces
AllowImplicitXmlnsDeclarationAttribute
and wiring in build tasks to support implicit/default xmlns usage. - Changes
XmlnsDefinitionAttribute
constructor parameter name and surfaces a newTarget
property. - Updates public API shipped/unshipped files, documentation, and solution to expose new types and behaviors.
Reviewed Changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 5 comments.
Show a summary per file
File | Description |
---|---|
PublicAPI/netstandard/PublicAPI.Shipped.txt | Updated XmlnsDefinitionAttribute ctor signature |
PublicAPI/net/*.Unshipped.txt & *.Shipped.txt (all platforms) | Added AllowImplicitXmlnsDeclarationAttribute and Target API |
Properties/AssemblyInfo.cs | Re-added x: xmlns prefix for XAML |
AllowImplicitXmlnsDeclarationAttribute.cs | New attribute to opt into implicit xmlns support |
Build.Tasks/XmlTypeExtensions.cs | Extended XML namespace gathering and added prefix extraction |
Build.Tasks/XamlTask.cs | Wired implicit xmlns logic into XAML parsing |
Build.Tasks/XamlCTask.cs | Updated XAML compilation to pass module context |
docs/XmlnsDefinitionAttribute.xml | Updated ctor sig in docs and added Target member |
Microsoft.Maui-vscode.sln | Included new SourceGen unit test project |
Comments suppressed due to low confidence (1)
src/Controls/src/Build.Tasks/XmlTypeExtensions.cs:45
- The new logic protecting built-in xmlns definitions and throwing BuildException on invalid entries lacks corresponding unit tests. Please add tests covering both allowed and prohibited XmlnsDefinitionAttribute scenarios to validate this behavior.
if ( attribute.XmlNamespace != XamlParser.MauiGlobal
src/Controls/docs/Microsoft.Maui.Controls/XmlnsDefinitionAttribute.xml
Outdated
Show resolved
Hide resolved
e9afcd0
to
adecc94
Compare
dd36fc7
to
5172f61
Compare
b1c705f
to
2c4b31a
Compare
Allow aggregating multiple xmlns into a single new global http://schemas.microsoft.com/dotnet/maui/global using XmlnsDefinition attribute, like this ```csharp [assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "http://schemas.microsoft.com/dotnet/2021/maui")] ``` the x: xmlns can not be aggregated, as it serves important purposes for the parsers this also brings #28090 to fix #28150 - fixes #28150 - fixes #28843 - closes #28090
protect maui and x: xmlns from overloading. - fixes #28836
6c167c6
to
de4b007
Compare
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.
Pull Request Overview
This PR simplifies XAML xmlns handling by introducing a project-scoped global xmlns, enabling implicit xmlns declarations, and protecting core namespaces through validation. It also updates public APIs and build tasks to support these features.
- Added
AllowImplicitXmlnsDeclarationAttribute
and updated XAML parsing to honor implicit xmlns. - Introduced validation to protect
maui
andx
namespaces and aggregated global xmlns logic in source generator. - Changed the public API signature of
XmlnsDefinitionAttribute
and updated its documentation.
Reviewed Changes
Copilot reviewed 59 out of 59 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
src/Controls/src/Core/PublicAPI/net-*/PublicAPI.Shipped.txt | Updated XmlnsDefinitionAttribute constructor signature to (string xmlNamespace, string target) |
src/Controls/src/Core/Properties/AssemblyInfo.cs | Added implicit x prefix for the XAML namespace |
src/Controls/src/Core/AllowImplicitXmlnsDeclarationAttribute.cs | New attribute to opt into implicit xmlns declarations |
src/Controls/src/Build.Tasks/XmlTypeExtensions.cs | Added protected xmlns validation and global xmlns gathering logic |
src/Controls/src/Build.Tasks/XamlTask.cs | Updated ParseXaml to use implicit xmlns via AllowImplicitXmlnsDeclarationAttribute |
src/Controls/src/Build.Tasks/XamlCTask.cs | Adjusted ParseXaml call to pass ModuleDefinition |
src/Controls/src/Build.Tasks/TypeReferenceExtensions.cs | Refactored system‐assembly comparison and fixed comparer logic |
src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs | Extended DataTemplate handling to include global xmlns and used helper |
src/Controls/src/Build.Tasks/ModuleDefinitionExtensions.cs | Enhanced type resolution to support global xmlns URIs |
src/Controls/src/Build.Tasks/CompiledConverters/BindablePropertyConverter.cs | Added IsOfAnyType helper to unify Maui vs. global xmlns checks |
src/Controls/docs/Microsoft.Maui.Controls/XmlnsDefinitionAttribute.xml | Updated docs for constructor parameter rename and added Target property docs |
Microsoft.Maui-vscode.sln | Added SourceGen.UnitTests project to the solution |
Comments suppressed due to low confidence (3)
src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs:536
- Operator precedence makes this evaluate as
(A && B) || C
, causing the global xmlns check to bypass the DataTemplate name check. Wrap the namespace conditions in parentheses:&& (B || C)
.
if (n.XmlType.Name == nameof(Microsoft.Maui.Controls.DataTemplate)
&& (n.XmlType.NamespaceUri == XamlParser.MauiUri) || n.XmlType.NamespaceUri == XamlParser.MauiGlobalUri)
src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs:96
- [nitpick] Remove this commented-out code block if it's no longer needed to keep the codebase clean.
// if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.MauiUri || target.XmlType.Name != nameof(VisualStateGroup))
src/Controls/docs/Microsoft.Maui.Controls/XmlnsDefinitionAttribute.xml:30
- The F# usage example still references 'clrNamespace' but the constructor parameter was renamed to 'target'. Update the usage to 'new XmlnsDefinitionAttribute (xmlNamespace, target)'.
<MemberSignature Language="F#" Value="new Microsoft.Maui.Controls.XmlnsDefinitionAttribute : string * string -> Microsoft.Maui.Controls.XmlnsDefinitionAttribute" Usage="new Microsoft.Maui.Controls.XmlnsDefinitionAttribute (xmlNamespace, clrNamespace)" />
@@ -10,10 +10,14 @@ | |||
<IsPackable>false</IsPackable> | |||
<DisableMSBuildAssemblyCopyCheck>true</DisableMSBuildAssemblyCopyCheck> | |||
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation> | |||
<DefineConstants>$(DefineConstants);MauiAllowImplicitXmlnsDeclaration</DefineConstants> | |||
<EnablePreviewFeatures>true</EnablePreviewFeatures> |
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.
those 2 lines enable the preview features
<DefineConstants>$(DefineConstants);MauiAllowImplicitXmlnsDeclaration</DefineConstants> | ||
<EnablePreviewFeatures>true</EnablePreviewFeatures> | ||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> | ||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath> |
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.
but those 2 are only there to help debugging
Co-authored-by: Copilot <[email protected]>
@@ -86,19 +92,19 @@ static string FindTypeNameForVisualState(IElementNode parent, IXmlLineInfo lineI | |||
//1. parent is VisualState, don't check that | |||
|
|||
//2. check that the VS is in a VSG | |||
if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.MauiUri || target.XmlType.Name != nameof(VisualStateGroup)) | |||
// if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.MauiUri || target.XmlType.Name != nameof(VisualStateGroup)) |
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.
// if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.MauiUri || target.XmlType.Name != nameof(VisualStateGroup)) |
var nsmgr = new XmlNamespaceManager(new NameTable()); | ||
nsmgr.AddNamespace("__f__", XamlParser.MauiUri); | ||
nsmgr.AddNamespace("__g__", XamlParser.MauiGlobalUri); | ||
if (allowImplicitXmlns) | ||
{ | ||
nsmgr.AddNamespace("", XamlParser.DefaultImplicitUri); | ||
foreach (var xmlnsPrefix in xmlnsCache.XmlnsPrefixes) | ||
nsmgr.AddNamespace(xmlnsPrefix.Prefix, xmlnsPrefix.XmlNamespace); | ||
} | ||
using var reader = XmlReader.Create(new StringReader(text.ToString()), | ||
new XmlReaderSettings { ConformanceLevel = allowImplicitXmlns ? ConformanceLevel.Fragment : ConformanceLevel.Document }, | ||
new XmlParserContext(nsmgr.NameTable, nsmgr, null, XmlSpace.None)); |
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.
This is a non-trivial piece of code and there are quite a few copies of it here and in the XamlC code. Would it make sense to move it to a separate method for consistency sake?
|
||
Assert.IsTrue(result1.TrackedSteps.All(s => s.Value.Single().Outputs.Single().Reason == IncrementalStepRunReason.New)); | ||
// Assert.IsTrue(result1.TrackedSteps.All(s => s.Value.Single().Outputs.Single().Reason == IncrementalStepRunReason.New)); |
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.
Why is this assert commented out?
{ | ||
var xaml = | ||
""" | ||
<?xml version="1.0" encoding="UTF-8"?> |
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.
The XML declaration is optional or mandatory?
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.
when your file encoding is "correct", it can be skipped
using Microsoft.Maui.Controls; | ||
using NUnit.Framework; | ||
|
||
[assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "Microsoft.Maui.Controls.Xaml.UnitTests.NSGlobalXmlnsWithXStatic")] |
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.
I'm a little confused now that I see the usage of this attribute. Do we expect the first parameter to be "http://schemas.microsoft.com/dotnet/maui/global"
in most cases? If yes, we could simplify this by having something like [assembly: GlobalXmlnsDefinition("MyNamespace")]
?
[assembly: XmlnsDefinition("http://companyone.com/schemas/toolkit", "CompanyOne.Controls")] | ||
[assembly: XmlnsPrefix("c1", "http://companyone.com/schemas/toolkit")] |
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.
Is it expected to use these two together? Would it be possible to allow the developer to completely skip declaring the URL and just do something like [assembly: XmlnsPrefix("c1", "CompanyOne.Controls")]
?
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.
there are often multiple XmlnsDefinitions for a single XmlnsPrefix. I'm worried that the apparent simplification will cause confusion
@@ -388,7 +388,7 @@ public void DesignTimeBuild() | |||
var xamlCStamp = IOPath.Combine(intermediateDirectory, "XamlC.stamp"); | |||
|
|||
//The assembly should not be compiled | |||
AssertDoesNotExist(assembly); | |||
//AssertDoesNotExist(assembly); |
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.
Why is this assert commented out?
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.
cause there are now multiple source gen contributing to an assembly being created
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.
Seems build is failing
/mnt/vss/_work/1/s/src/Controls/src/Build.Tasks/TypeReferenceExtensions.cs(28,8): error CS0103: The name 'IsSystemAssemvly' does not exist in the current context [/mnt/vss/_work/1/s/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj]
/mnt/vss/_work/1/s/src/Controls/src/Build.Tasks/TypeReferenceExtensions.cs(28,34): error CS0103: The name 'IsSystemAssemvly' does not exist in the current context [/mnt/vss/_work/1/s/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj]
/mnt/vss/_work/1/s/src/Controls/src/Build.Tasks/TypeReferenceExtensions.cs(36,8): error CS0103: The name 'IsSystemAssemvly' does not exist in the current context [/mnt/vss/_work/1/s/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj]
0 Warning(s)
3 Error(s)
Using [assembly: XamlUsing("MyApp.ViewModels")]
[assembly: XamlUsing("MyApp.ViewModels", prefix: "vm")] The optional |
Co-authored-by: Copilot <[email protected]>
Description of Change
This PR includes multiple changes related to xmlns, as tracked by #28836.
New global xmlns
http://schemas.microsoft.com/dotnet/maui/global
is a new xmlns that you can use to aggregate multiple xmlns together.The scope of it is local to the project.
By default, it contains the maui xmlns (sourcegenerated) YourNamespace and YourNamespace.Pages (enabled by the updated template.
You can extend this in e.g.
GlobalXmlns.cs
added by the template (#29203), or adding assembly levelXmlnsDefinition
anywhere.You can ad CLR namespaces as usual, but also other xmlns
[assembly:XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "http://mycompany.com/schema/myxmlns")]
That global xmlns also have a XmlnsPrefix "global" associated to it.
IMPORTANT NOTE: you can not aggregate the x xmlns into the global one. It plays a special role for the parsers and inflators.
This change is implemented using a source generator, so there's no requirement to change any other tool consuming xaml making use of this
Make the xmlns delcarations in XAML implicit
The XAML inflators uses the global xmlns as default, and preloads all other xmlns declared by a XmlnsDefinition that also have a XmlnsPrefix attribute. e.g. the x: prefix is there to be used without the need of being declared.
This part is opt-in, you can enable it by setting
in your
.csproj
Protect some xmlns
with a fix for #28150, it becomes necessary to avoid the overload of the maui, and x, xmlns namespaces.
Issues Fixed
fixes make the default xmlns declaration optional #28849
fixes pre-defined xmlns prefixes #28850
fixes Implicit global xmlns #28847
fixes XAML xmlns simplifications #28836
fixes XmlnsDefinitonAttribute is not supported for "this" assembly #28150
fixes xmlns aggregation #28843
fixes protect maui xmlns from overloading #28839
closes Support XmlnsDefinitionAttribute in "this" assembly #28090
closes [X] implicit xmlns declarations #29181
closes [X] global xmlns #28969
closes [X] Protect some xmlns #28909