Simpler XAML in .NET MAUI 10
Building UI in .NET MAUI with XAML continues to be the most popular approach. It’s easy to see the nesting structure of your UI, works for most use cases with hot reload, and it supports powerful state flow with data binding. One of the downsides is how verbose it can become. Every page requires you to declare the namespaces for any types used, provide prefixes for them, and of course use them. You’re likely a better developer than I am, but I very often use a different prefix for the same namespace in different files making quite a mess.
.NET 6 introduced global and implicit usings for C# which greatly reduced the using statements at the head of many C# files. Now in .NET 10 starting with Preview 5 we are introducing the same for XAML so you can declare your namespaces and prefixes in a single file and use them throughout. In fact, you can now omit the use of prefixes altogether!
Implicit Namespaces
This update begins by switching the global namespace that all XAML files used in .NET MAUI from xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
to xmlns="http://schemas.microsoft.com/dotnet/maui/global"
. Now there is a truly global namespace unique to your application where we can pack other namespaces for use throughout the codebase.
Opt-in to the implicit namespaces by adding this configuration to your project file.
<PropertyGroup>
<DefineConstants>$(DefineConstants);MauiAllowImplicitXmlnsDeclaration</DefineConstants>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>
Now your project will implicitly include these 2 namespaces which you’ve been accustomed to seeing in every XAML file since .NET MAUI first shipped.
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Because x:
is used by the XAML inflator, you still need to use that prefix. With this change alone, your XAML for a view gets much tighter.
Before
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Pages.MyContentPage">
</ContentPage>
After
<ContentPage x:Class="MyApp.Pages.MyContentPage">
</ContentPage>
Global Namespaces
As you start to include classes of your own and from any of the many useful NuGet packages for .NET MAUI, the stack of xmlns
in your XAML starts to grow like a layer cake. This is the MainPage
from my app Telepathy
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pageModels="clr-namespace:Telepathic.PageModels"
xmlns:viewModels="clr-namespace:Telepathic.ViewModels"
xmlns:models="clr-namespace:Telepathic.Models"
xmlns:converters="clr-namespace:Telepathic.Converters"
xmlns:controls="clr-namespace:Telepathic.Pages.Controls"
xmlns:sf="clr-namespace:Syncfusion.Maui.Toolkit.TextInputLayout;assembly=Syncfusion.Maui.Toolkit"
xmlns:cards="clr-namespace:Syncfusion.Maui.Toolkit.Cards;assembly=Syncfusion.Maui.Toolkit"
xmlns:b="clr-namespace:Syncfusion.Maui.Toolkit.Buttons;assembly=Syncfusion.Maui.Toolkit"
xmlns:pullToRefresh="clr-namespace:Syncfusion.Maui.Toolkit.PullToRefresh;assembly=Syncfusion.Maui.Toolkit"
xmlns:bottomSheet="clr-namespace:Syncfusion.Maui.Toolkit.BottomSheet;assembly=Syncfusion.Maui.Toolkit"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:aloha="clr-namespace:AlohaKit.Animations;assembly=AlohaKit.Animations"
xmlns:effectsView="http://schemas.syncfusion.com/maui/toolkit"
x:Class="Telepathic.Pages.MainPage"
x:DataType="pageModels:MainPageModel"
Title="{Binding Today}">
</ContentPage>
Yikes! Many of my XAML files use the same namespaces over and over such as pageModels
, models
, converters
, controls
, and so on. To globalize these, I created a GlobalXmlns.cs
file where I can register these namespaces using XmlnsDefinition
.
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Telepathic.PageModels")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Telepathic.Models")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Telepathic.Converters")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Telepathic.Pages.Controls")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Telepathic.ViewModels")]
I can also use the same to globalize third-party controls like the Syncfusion Toolkit for .NET MAUI, the Community Toolkit for .NET MAUI, and AlohaKit Animations used in this file.
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Syncfusion.Maui.Toolkit.TextInputLayout", AssemblyName = "Syncfusion.Maui.Toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Syncfusion.Maui.Toolkit.Cards", AssemblyName = "Syncfusion.Maui.Toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Syncfusion.Maui.Toolkit.Buttons", AssemblyName = "Syncfusion.Maui.Toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Syncfusion.Maui.Toolkit.PullToRefresh", AssemblyName = "Syncfusion.Maui.Toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"Syncfusion.Maui.Toolkit.BottomSheet", AssemblyName = "Syncfusion.Maui.Toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"http://schemas.syncfusion.com/maui/toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"http://schemas.microsoft.com/dotnet/2022/maui/toolkit")]
[assembly: XmlnsDefinition(
"http://schemas.microsoft.com/dotnet/maui/global",
"AlohaKit.Animations", AssemblyName = "AlohaKit.Animations")]
After this I can remove all those declarations from the head of the file, resulting in a much cleaner read.
<ContentPage x:Class="Telepathic.Pages.MainPage"
x:DataType="MainPageModel"
Title="{Binding Today}">
</ContentPage>
Namespace Prefixes
Now that the xmlns
are all gone, you may be wondering about the prefixes that had been defined in order to reference those controls in XAML. Well, you no longer need them! Notice in the previous example the x:DataType
omits the pageModels:
prefix previously required.
Let’s look at another example from this same page.
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="models:ProjectTask">
<controls:TaskView
TaskCompletedCommand="{Binding CompletedCommand,
Source={RelativeSource AncestorType={x:Type pageModels:MainPageModel}},
x:DataType=pageModels:MainPageModel}"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
After
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="ProjectTask">
<TaskView
TaskCompletedCommand="{Binding CompletedCommand,
Source={RelativeSource AncestorType={x:Type MainPageModel}},
x:DataType=MainPageModel}"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
Disambiguating Types
There will be times when you have types that collide and you’ll need to disambiguate them. I ran into this in another application where I have a custom control called FlyoutItem
in my namespace ControlGallery.Views
. In the XAML file it was being reference like <views:FlyoutItem />
and all was well. When I added ControlGallery.Views
to the global namespace and removed the views:
prefix, I encountered a collision because .NET MAUI already has a type FlyoutItem
!
One way I could solve this would be to use the full path with namespace in the XAML like <ControlGallery.Views.FlyoutItem />
. That is pretty long and not my preference.
Instead, there’s another attribute I can use alongside XmlnsDefinition
and that’s XmlnsPrefix
. Back in the GlobalXmlns.cs
I can add a prefix for this namespace that’ll be usable globally in my application.
[assembly: XmlnsPrefix(
"clr-namespace:ControlGallery.Views",
"views")]
Now once again in XAML I can use that prefix like <views:FlyoutItem />
.
Note
Before you go all in on this, be aware it’s a preview and there are issues to be ironed out. For example, the XAML Language Service needs some love to make it aware of what’s happening so you don’t get red squiggles everywhere. Additionally, work needs to be done to address the negative startup and runtime performance impact.Resources
- What’s New in .NET MAUI for .NET 10
- Download .NET 10 Preview
- .NET MAUI XAML Namespaces Documentation
Known Issues
- Debug builds are currently slower to startup
- Runtime view inflation is slower
- XAML editors incorrectly report unknown types via red squiggles (e.g. XLS0414)
- Declaring prefixes for namespaces in the project requires including
clr-namespace:
Feedback
You can get started by installing .NET 10 Preview 5 with the .NET MAUI workload or Visual Studio 17.14 Preview, and then creating a new project.
dotnet new maui -n LessXamlPlease
We need your feedback! Give this a go and let us know what you think by opening an issue on GitHub or sending me a note directly at [email protected].
The post Simpler XAML in .NET MAUI 10 appeared first on .NET Blog.