{"id":32603,"date":"2021-04-09T12:18:31","date_gmt":"2021-04-09T19:18:31","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=32603"},"modified":"2021-04-09T12:18:31","modified_gmt":"2021-04-09T19:18:31","slug":"announcing-net-multi-platform-app-ui-preview-3","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-multi-platform-app-ui-preview-3\/","title":{"rendered":"Announcing .NET Multi-platform App UI Preview 3"},"content":{"rendered":"<p><span class=\"x x-first x-last\">With <\/span>.NET <span class=\"pl-c1\">6<\/span> Preview <span class=\"pl-c1\">3<\/span> we are shipping the latest progress for mobile <span class=\"pl-k\">and<\/span> desktop development with .NET Multi-platform App UI. This release adds the Windows platform with WinUI <span class=\"pl-c1\">3<\/span>, improves the base application <span class=\"pl-k\">and<\/span> startup builder, adds native lifecycle events, <span class=\"pl-k\">and<\/span> continues to add more UI controls <span class=\"pl-k\">and<\/span> layout capabilities. We are also introducing new semantic properties for accessibility. As we explore each of these in a bit more detail, we invite you to <code>dotnet new<\/code> along with us <span class=\"pl-k\">and<\/span> share your feedback.<\/p>\n<h2>Windows Desktop Now Supported<\/h2>\n<p>Project Reunion 0.5 has shipped! Now Windows joins Android, iOS, and macOS as target platforms you can reach with .NET MAUI! To get started, follow the <a href=\"https:\/\/docs.microsoft.com\/windows\/apps\/project-reunion\/get-started-with-project-reunion\">Project Reunion installation instructions<\/a>. For this release we have created a <a href=\"https:\/\/github.com\/dotnet\/net6-mobile-samples\">sample project<\/a> that you can explore and run from the 16.10 preview of Visual Studio 2019.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2021\/04\/maui-winui.png\" alt=\".NET MAUI running on WinUI 3\" \/><\/p>\n<p>Once we have the necessary .NET 6 build infrastructure for Project Reunion, we will add Windows to our single project templates.<\/p>\n<h2>Getting Started<\/h2>\n<p>As we are still in the early stages of preview, the process of installing all the dependencies you need for mobile and desktop development is a bit manual. To help ourselves, and you, <a href=\"https:\/\/github.com\/redth\">Jonathan Dick<\/a> has put together a useful <code>dotnet tool<\/code> that evaluates your system and gathers as many of the required pieces as it can. To get started, install <code>maui-check<\/code> globally from the command line:<\/p>\n<pre><code class=\"cli\">dotnet tool install -g Redth.Net.Maui.Check\r\n<\/code><\/pre>\n<p>Source: <a href=\"https:\/\/github.com\/Redth\/dotnet-maui-check\">https:\/\/github.com\/Redth\/dotnet-maui-check<\/a><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2021\/04\/maui-check.png\" alt=\"maui-check command line tool\" \/><\/p>\n<p>Now run <code>&gt; maui-check<\/code> and follow the instructions. Once you succeed, you&#8217;re ready to create your first app:<\/p>\n<pre><code class=\"cli\">dotnet new maui -n HelloMaui\r\n<\/code><\/pre>\n<p>Step-by-step instructions for installing and getting started may also be found at <a href=\"https:\/\/github.com\/dotnet\/maui\/wiki\/Getting-Started\">https:\/\/github.com\/dotnet\/maui\/wiki\/Getting-Started<\/a>.<\/p>\n<h2>Your First Application<\/h2>\n<p>.NET MAUI starts every application using the <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/microsoft.extensions.hosting.hostbuilder\">Microsoft.Extensions HostBuilder<\/a>. This provides a consistent pattern for application developers as well as library maintainers to quickly develop native applications. Each platform has a different starting point, and the consistent point of entry for your application is <code>Startup.cs<\/code>. Here is the most basic example:<\/p>\n<pre><code class=\"csharp\">public class Startup : IStartup\r\n{\r\n    public void Configure(IAppHostBuilder appBuilder)\r\n    {\r\n        appBuilder\r\n            .UseMauiApp&lt;App&gt;();\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>This is where you can do such things as register fonts and register compatibility for Xamarin.Forms renderers or your own custom renderers. This is also where you introduce your <code>App<\/code>, an implementation of <code>Application<\/code> which is responsible for (at least) creating a new <code>Window<\/code>:<\/p>\n<pre><code class=\"csharp\">public partial class App : Application\r\n{\r\n    public override IWindow CreateWindow(IActivationState activationState)\r\n    {\r\n        return new MainWindow();\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>To complete the path to your content, a view is added to the <code>MainWindow<\/code>:<\/p>\n<pre><code class=\"csharp\">public class MainWindow : IWindow\r\n{\r\n    public MainWindow()\r\n    {\r\n        Page = new MainPage();\r\n    }\r\n\r\n    public IPage Page { get; set; }\r\n\r\n    public IMauiContext MauiContext { get; set; }\r\n}\r\n<\/code><\/pre>\n<p>And that&#8217;s it! You now have content in a window.<\/p>\n<h2>Native Lifecycle Events<\/h2>\n<p>Expanding on the startup extensions, Preview 3 introduces <code>ConfigureLifecycleEvents<\/code> for easily hooking into native platform lifecycle events. This is an important introduction, especially for the single project experience, to simplify initialization and configuration needed by many libraries.<\/p>\n<p>As a basic example, you can hook to the Android back button event and handle it as needed:<\/p>\n<pre><code class=\"csharp\">public class Startup : IStartup\r\n{\r\n    public void Configure(IAppHostBuilder appBuilder)\r\n    {\r\n        appBuilder\r\n            .UseMauiApp&lt;App&gt;()\r\n            .ConfigureLifecycleEvents(lifecycle =&gt; {\r\n                #if ANDROID\r\n                lifecycle.AddAndroid(d =&gt; {\r\n                    d.OnBackPressed(activity =&gt; {\r\n                        System.Diagnostics.Debug.WriteLine(\"Back button pressed!\");\r\n                    });\r\n                });\r\n                #endif\r\n            });\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Now let&#8217;s look at how libraries can use these methods to streamline their platform initialization work. Essentials (Microsoft.Maui.Essentials), a library for cross-platform non-UI services that is now a part of .NET MAUI, makes use of this to configure everything needed for all platforms in a single location:<\/p>\n<pre><code class=\"csharp\">public class Startup : IStartup\r\n{\r\n    public void Configure(IAppHostBuilder appBuilder)\r\n    {\r\n        appBuilder\r\n            .UseMauiApp&lt;App&gt;()\r\n            .ConfigureEssentials(essentials =&gt;\r\n            {\r\n                essentials\r\n                    .UseVersionTracking()\r\n                    .UseMapServiceToken(\"YOUR-KEY-HERE\");\r\n            });\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Within the Essentials code, you can see how the <code>ConfigureEssentials<\/code> extension method is created and hooks into the platform lifecycle events to greatly streamline cross-platform native configuration.<\/p>\n<pre><code class=\"csharp\">public static IAppHostBuilder ConfigureEssentials(this IAppHostBuilder builder, Action&lt;HostBuilderContext, IEssentialsBuilder&gt; configureDelegate = null)\r\n{\r\n    builder.ConfigureLifecycleEvents(life =&gt;\r\n    {\r\n#if __ANDROID__\r\n        Platform.Init(MauiApplication.Current);\r\n\r\n        life.AddAndroid(android =&gt; android\r\n            .OnRequestPermissionsResult((activity, requestCode, permissions, grantResults) =&gt;\r\n            {\r\n                Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);\r\n            })\r\n            .OnNewIntent((activity, intent) =&gt;\r\n            {\r\n                Platform.OnNewIntent(intent);\r\n            })\r\n            .OnResume((activity) =&gt;\r\n            {\r\n                Platform.OnResume();\r\n            }));\r\n#elif __IOS__\r\n        life.AddiOS(ios =&gt; ios\r\n            .ContinueUserActivity((application, userActivity, completionHandler) =&gt;\r\n            {\r\n                return Platform.ContinueUserActivity(application, userActivity, completionHandler);\r\n            })\r\n            .OpenUrl((application, url, options) =&gt;\r\n            {\r\n                return Platform.OpenUrl(application, url, options);\r\n            })\r\n            .PerformActionForShortcutItem((application, shortcutItem, completionHandler) =&gt;\r\n            {\r\n                Platform.PerformActionForShortcutItem(application, shortcutItem, completionHandler);\r\n            }));\r\n#elif WINDOWS\r\n        life.AddWindows(windows =&gt; windows\r\n            .OnLaunched((application, args) =&gt;\r\n            {\r\n                Platform.OnLaunched(args);\r\n            }));\r\n#endif\r\n    });\r\n\r\n    if (configureDelegate != null)\r\n        builder.ConfigureServices&lt;EssentialsBuilder&gt;(configureDelegate);\r\n\r\n    return builder;\r\n}\r\n<\/code><\/pre>\n<p>You can see the <a href=\"https:\/\/github.com\/dotnet\/maui\/blob\/main\/src\/Controls\/samples\/Controls.Sample\/Extensions\/EssentialsExtensions.cs#L29\">full class on dotnet\/maui<\/a>. We are excited to see more libraries take advantage of this pattern to streamline their usage.<\/p>\n<h2>Updates to Controls and Layouts<\/h2>\n<p>Work continues enabling more controls, properties, and layout options in .NET MAUI, in addition to the existing compatibility renderers brought in from Xamarin.Forms. If you begin your application with a startup like the code above, then you&#8217;ll be using only the handlers currently implemented. To see what&#8217;s currently implemented, you can review the <a href=\"https:\/\/github.com\/dotnet\/maui\/tree\/main\/src\/Core\/src\/Handlers\">Handlers folder at dotnet\/maui<\/a>.<\/p>\n<p>To track incoming work we have a <a href=\"https:\/\/github.com\/dotnet\/maui\/projects\/4\">Project Board<\/a> setup for all the handlers we are accepting pull requests for. Several developers have already contributed, and early feedback indicates this architecture provides a much improved experience for ease of contribution.<\/p>\n<blockquote><p>&#8220;Porting handlers are fun. Any mid-senior developer can handle if they had a little bit of a proper understanding of how Xamarin Forms renderers and how Xamarin in general work.&#8221; &#8211; Burak<\/p><\/blockquote>\n<p>Special thanks to these community contributors:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/almirvuk\">almirvuk<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/566\">Implement CharacterSpacing property in Entry handler<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/AmrAlSayed0\">AmrAlSayed0<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/538\">Implemented LineHeight on Label<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/bkaankose\">bkaankose<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/564\">Entry ClearButtonVisibility handler<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/brunck\">brunck<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/573\">Port Editor Placeholder text and color properties<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/hevey\">hevey<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/515\">Implement IsTextPredictionEnabled property on Editor<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/pictos\">pictos<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/503\">Port font to Editor<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/rogihee\">rogihee<\/a>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/maui\/pull\/493\">Switch Entry and Editor from EditText to AppCompatEditText<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Layouts have also received some updates in Preview 3. The <code>Grid<\/code> now supports absolute sizes and auto (sizes to the content). LayoutAlignment options are also now available for <code>Grid<\/code> and <code>StackLayout<\/code> so you can begin positioning views with <code>HorizontalLayoutAlignment<\/code> and <code>VerticalLayoutAlignment<\/code> properties.<\/p>\n<h2>Semantic Properties for Accessibility<\/h2>\n<p>We have been working with many customers to better understand common difficulties around implementing accessibility across multiple native platforms, and how we might make this easier in .NET MAUI. One of the initiatives to come from this is adding new semantic properties to map cross-platform properties to native accessibility properties.<\/p>\n<pre><code class=\"xaml\">&lt;Label \r\n    Text=\"Welcome to .NET MAUI!\"\r\n    SemanticProperties.HeadingLevel=\"Level1\"\r\n    FontSize=\"32\"\r\n    HorizontalOptions=\"CenterAndExpand\" \/&gt;\r\n\r\n&lt;Label \r\n    Style=\"{DynamicResource Glyph}\" \r\n    Text=\"\uf388\" \r\n    SemanticProperties.Description=\"Heart\" \/&gt;\r\n\r\n&lt;Label \r\n    Text=\"Click the button. You know you want to!\" \r\n    FontSize=\"18\"\r\n    x:Name=\"CounterLabel\"\r\n    HorizontalOptions=\"CenterAndExpand\" \/&gt;\r\n\r\n&lt;Button \r\n    Text=\"Click Me!\" \r\n    Clicked=\"OnButtonClicked\"\r\n    SemanticProperties.Hint=\"Counts the number of times you click\"\/&gt;\r\n<\/code><\/pre>\n<p>For more information, the original specification and discussion is on <a href=\"https:\/\/github.com\/dotnet\/maui\/issues\/469\">this dotnet\/maui issue<\/a>.<\/p>\n<h2>Share Your Feedback<\/h2>\n<p>We are excited for this release, and look forward to your feedback. Join us at <a href=\"https:\/\/github.com\/dotnet\/maui\">dotnet\/maui<\/a> and let us know what you think of these improvements.<\/p>\n<p>With each new preview of .NET 6 you can expect more and more capabilities to &#8220;light up&#8221; in .NET MAUI. For now, please focus on the &#8220;dotnet new&#8221; experience. Xamarin.Forms developers should look forward to a mid-year release when we&#8217;ll encourage more migration exploration.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET Multi-platform App UI updates in .NET 6 Preview 3<\/p>\n","protected":false},"author":553,"featured_media":32601,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7233],"tags":[4],"class_list":["post-32603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-maui","tag-net"],"acf":[],"blog_post_summary":"<p>.NET Multi-platform App UI updates in .NET 6 Preview 3<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/32603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/553"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=32603"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/32603\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/32601"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=32603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=32603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=32603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}