Skip to content

Commit

Permalink
Merge pull request #1691 from unoplatform/dev/nr/maui
Browse files Browse the repository at this point in the history
feat: Embedding
  • Loading branch information
nickrandolph authored Jul 25, 2023
2 parents 0c2d807 + 5cbf98e commit e20785c
Show file tree
Hide file tree
Showing 181 changed files with 6,797 additions and 72 deletions.
3 changes: 2 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
<Build_Android>true</Build_Android>
<Build_iOS>true</Build_iOS>
<Build_MacOS>true</Build_MacOS>
<Build_Windows>true</Build_Windows>
<Build_Windows Condition="$([MSBuild]::IsOSPlatform('windows'))">true</Build_Windows>
<Build_Windows Condition="!$([MSBuild]::IsOSPlatform('windows'))">false</Build_Windows>
</PropertyGroup>

<Import Project="DebugPlatforms.props" Condition="exists('DebugPlatforms.props')" />
Expand Down
5 changes: 5 additions & 0 deletions build/ci/templates/dotnet-install-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ steps:
errorActionPreference: continue
ignoreLASTEXITCODE: true
retryCountOnTaskFailure: 3
- powershell: |
dotnet workload install maui --source https://api.nuget.org/v3/index.json
dotnet workload install android ios maccatalyst tvos macos maui wasm-tools --source https://api.nuget.org/v3/index.json
displayName: Maui workloads
92 changes: 92 additions & 0 deletions doc/Learn/Tutorials/Maui/HowTo-Use3rdPartLibs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
uid: Learn.Tutorials.Maui.HowToUse3rdPartLibs
---

# How-To: Install and use third part libraries on Uno apps with Maui Embedding

When working in an application project, you may need to install a third party library. This guide will show you how to install and use a third party library in your Uno app with Maui Embedding.

For this sample we will use the `CommunityToolkit.Maui` library.

## Step-by-steps

### 1. Installing the NuGet package

On Visual Studio you can use the `Nuget Package Manager` to install the `CommunityToolkit.Maui` package. Install it on your class library project and mobile and Windows project (because this package support those platforms).

To verify if the package is installed you can look on your csproj file and check if the package is there. It should be something like this:

```xml
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="2.0.0" />
</ItemGroup>
```

### 2. Using the library

In order to use the library we need to initialize it, we do that during the app initialization. So go to your `App.cs` file and add the following code:

```csharp
using using CommunityToolkit.Maui;

protected async override void OnLaunched(LaunchActivatedEventArgs args)
{
var builder = this.CreateBuilder(args)
.UseMauiEmbedding(maui =>
{
maui.UseMauiCommunityToolkit();
})
// the rest of your configuration
}
```

> [!INFO]
> If you are using other libraries that targets .NET MAUI and requires initialization, you can do it inside the lambda function on `UseMauiEmbedding` call.
Now let's use it on our Page. For that you have to open your XAML page and add the necessary namespaces and the controls you want to use. In this sample we will use the `DrawingView` control.

```xml
<Page
x:Class="MauiEmbedding.Presentation.MCTControlsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:uem="using:Uno.Extensions.Maui"
xmlns:local="using:MauiEmbedding.Presentation"
xmlns:maui="using:Microsoft.Maui.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:uen="using:Uno.Extensions.Navigation.UI"
xmlns:utu="using:Uno.Toolkit.UI"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
NavigationCacheMode="Required"
mc:Ignorable="d">

<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<embed:MauiContent>
<maui:ScrollView>
<maui:ScrollView.Content>
<maui:VerticalStackLayout Spacing="16">
<toolkit:DrawingView
HeightRequest="300"
IsMultiLineModeEnabled="true"
LineColor="{embed:MauiColor Value='#FF0000'}"
LineWidth="5"
WidthRequest="300" />
</maui:VerticalStackLayout>
</maui:ScrollView.Content>
</maui:ScrollView>
</embed:MauiContent>
</StackPanel>
</Page>
```

Let's take a moment and review this piece of code. First we added the `toolkit` namespace, this is the namespace that contains the controls from the `CommunityToolkit.Maui` library. In order to consume the `DrawingView` control. We need to use the `MauiContent` control, that lives on `uem` namespace, this control holds all the .NET MAUI types (layouts, controls, converters, etc), you can't use .NET MAUI types outside this control.

Also, Uno Platform does not convert the `Color` type from .NET MAUI to the WinUI `Color`, so we need to use the `MauiColor` markup extension for the conversion, as you can see in the `LineColor` property.

### 3. Conclusion

At this point, running the app should show the `DrawingView` control and allow interactions with it.
88 changes: 88 additions & 0 deletions doc/Overview/Maui/MauiOverview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
uid: Overview.Maui
---
# .NET Maui Embedding

.NET Maui Embedding provides limited support for Uno Applications to make use of 3rd party control libraries when the required app platforms match one of those available from .NET MAUI.

## Initialization

After installing the `Uno.Extensions.Maui.WinUI` NuGet package you will need to update your App.cs in the core/shared project of your Uno Platform Project.

```cs
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
this.UseMauiEmbedding();
}
```

Similarly if you are using Uno.Extensions.Hosting for Dependency Injection you can call the `UseMauiEmbedding()` extension off of the `IApplicationBuilder` like:

```cs
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var builder = this.CreateBuilder(args)
.UseMauiEmbedding();
}
```

In the event that your 3rd party control library requires initialization on the `MauiAppBuilder` you can initialize those libraries by simply providing a delegate for the `MauiAppBuilder` in the `UseMauiEmbedding()` extension method:

```cs
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var builder = this.CreateBuilder(args)
.UseMauiEmbedding(maui => maui
.UseTelerikControls())
}
```

## Getting Started

With Maui Initialized we are now able to make use of the MauiContent control provided by Uno.Extensions.Maui.WinUI.

```xml
<Page x:Class="DemoTelerikApp.Presentation.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:embed="using:Uno.Extensions.Maui"
xmlns:maui="using:Microsoft.Maui.Controls"
Background="{ThemeResource BackgroundBrush}">

<embed:MauiContent>
<maui:Label Text="Hello From .NET MAUI &amp; Uno Platform" />
</embed:MauiContent>
</Page>
```

### Resources & Styles

When the MauiContent is created it will walk the Visual Tree and look for any parents including `Application.Current` which have a ResourceDictionary which has Resources and/or Styles. It will then do it's best to bring these over to the available MAUI Resources. This includes being able to reuse Colors, Brushes, Thickness, and Converters as well as some limited support for Styles.

### XAML Extensions

There are several XAML Extensions that you may decide to make use of while building an app with .NET MAUI Embedding.

- MauiBinding - As the name suggests this will allow you to create a binding to your DataContext. **NOTE** You can not use `x:Bind` or `Binding` on a MAUI Control.
- MauiColor: If you want to be able to directly apply a Hex string or `Color` name to a `Color` property on a MAUI Control you can use the `MauiColor` Extension to provide that value.
- MauiThickness: If you want to be able to directly apply a `Thickness`, you can use the `MauiThickness` extension to provide a value like `10`, `10,20`, or `10,20,10,5`
- MauiResource: As explained in the previous section, the `MauiContent` control will bring over the WinUI Resources automatically to make it easier to provide consistent styling even within the `MauiContent` of your View. This will allow you to provide a resource Key to apply to a given property.

```xml
<maui:VerticalStackLayout BackgroundColor="{embed:MauiColor Value='#ABABAB'}">
<maui:Label Text="{embed:MauiBinding Path='Message'}" />
</maui:VerticalStackLayout>
```

### Limitations and Known issues

- Some controls like the `ScrollView` from .NET MAUI will not have the `Content` property automatically recognized by the XAML compiler. As a result you will need to be more verbose with these controls like:
```xml
<ScrollView>
<ScrollView.Content>
<!-- My Content -->
</ScrollView.Content>
</ScrollView>
```
- Common type conversions such as hex string or color name to Maui Graphics Color will not work with the XAML Compiler. Similarly types like Thickness `10` or `10,20` will not be picked up and converted by the XAML Compiler. For these primitive types especially it is recommended to simply provide a WinUI Thickness or Color in your Resource Dictionary. These native types will be automatically converted to MAUI types and available to use with the `MauiResource` XAML Extension.
- .NET MAUI Hot Reload will throw an exception and cause the app the crash. You will need to disable this in Visual Studio for now.
15 changes: 15 additions & 0 deletions samples/MauiEmbedding/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": "Uno Platform Mobile",
"type": "Uno",
"request": "launch",
// any Uno* task will do, this is simply to satisfy vscode requirement when a launch.json is present
"preLaunchTask": "Uno: android | Debug | android-x64"
},
]
}
56 changes: 56 additions & 0 deletions samples/MauiEmbedding/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<Project>
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<DebugType>portable</DebugType>
<DebugSymbols>True</DebugSymbols>

<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<WarningsNotAsErrors>NU1009</WarningsNotAsErrors>
<NoWarn>$(NoWarn);CA1416;NU1507;NU1009</NoWarn>

<DefaultLanguage>en</DefaultLanguage>

<IsAndroid>false</IsAndroid>
<IsIOS>false</IsIOS>
<IsMac>false</IsMac>
<IsMacCatalyst>false</IsMacCatalyst>
<IsWinAppSdk>false</IsWinAppSdk>
<_UseTelerik>false</_UseTelerik>
</PropertyGroup>

<Choose>
<When Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
<PropertyGroup>
<IsAndroid>true</IsAndroid>
<SupportedOSPlatformVersion>21.0</SupportedOSPlatformVersion>
</PropertyGroup>
</When>
<When Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
<PropertyGroup>
<IsIOS>true</IsIOS>
<SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
</PropertyGroup>
</When>
<When Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos'">
<PropertyGroup>
<IsMac>true</IsMac>
<SupportedOSPlatformVersion>10.14</SupportedOSPlatformVersion>
</PropertyGroup>
</When>
<When Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">
<PropertyGroup>
<IsMacCatalyst>true</IsMacCatalyst>
<SupportedOSPlatformVersion>14.0</SupportedOSPlatformVersion>
</PropertyGroup>
</When>
<When Condition="$(TargetFramework.Contains('windows10'))">
<PropertyGroup>
<IsWinAppSdk>true</IsWinAppSdk>
<SupportedOSPlatformVersion>10.0.18362.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
</PropertyGroup>
</When>
</Choose>
</Project>
6 changes: 6 additions & 0 deletions samples/MauiEmbedding/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project>
<ItemGroup>
<!-- Removes native usings to avoid Ambiguous reference -->
<Using Remove="@(Using->HasMetadata('Platform'))" />
</ItemGroup>
</Project>
25 changes: 25 additions & 0 deletions samples/MauiEmbedding/Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project ToolsVersion="15.0">
<ItemGroup>
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.756" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.3.230602002" />
<PackageVersion Include="SkiaSharp" Version="2.88.4-preview.89" />
<PackageVersion Include="SkiaSharp.Views.Uno.WinUI" Version="2.88.4-preview.89" />
<PackageVersion Include="SkiaSharp.NativeAssets.iOS" Version="2.88.4-preview.89" />
<PackageVersion Include="Uno.Core.Extensions.Logging.Singleton" Version="4.0.1" />
<PackageVersion Include="Uno.Extensions.Logging.OSLog" Version="1.4.0" />
<PackageVersion Include="Uno.Material.WinUI" Version="3.0.0-dev.262" />
<PackageVersion Include="Uno.Dsp.Tasks" Version="1.1.0" />
<PackageVersion Include="Uno.Toolkit.WinUI" Version="3.1.0-dev.24" />
<PackageVersion Include="Uno.Toolkit.WinUI.Material" Version="3.1.0-dev.24" />
<PackageVersion Include="Uno.Resizetizer" Version="1.2.0-dev.13" />
<PackageVersion Include="Uno.UI.Adapter.Microsoft.Extensions.Logging" Version="5.0.0-dev.1610" />
<PackageVersion Include="Uno.UniversalImageLoader" Version="1.9.36" />
<PackageVersion Include="Uno.WinUI" Version="5.0.0-dev.1610" />
<PackageVersion Include="Uno.WinUI.RemoteControl" Version="5.0.0-dev.1610" />
<PackageVersion Include="CommunityToolkit.Maui" Version="2.0.0" />
<PackageVersion Include="Telerik.UI.for.Maui" Version="5.1.0" Condition="$(_UseTelerik)" />
<PackageVersion Include="Esri.ArcGISRuntime.Maui" Version="200.1.0" />
</ItemGroup>
</Project>
36 changes: 36 additions & 0 deletions samples/MauiEmbedding/MauiEmbedding-vsmac.slnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"solution": {
"path": "MauiEmbedding.sln",
"projects": [
"..\\..\\src\\Uno.Extensions.Configuration\\Uno.Extensions.Configuration.csproj",
"..\\..\\src\\Uno.Extensions.Core.Generators\\Uno.Extensions.Core.Generators.csproj",
"..\\..\\src\\Uno.Extensions.Core.UI\\Uno.Extensions.Core.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Core\\Uno.Extensions.Core.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.WinUI.Skia.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.WinUI.Wasm.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Hosting\\Uno.Extensions.Hosting.csproj",
"..\\..\\src\\Uno.Extensions.Localization.UI\\Uno.Extensions.Localization.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Localization\\Uno.Extensions.Localization.csproj",
"..\\..\\src\\Uno.Extensions.Logging.Serilog\\Uno.Extensions.Logging.Serilog.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.WinUI.Skia.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.WinUI.Wasm.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Maui.UI\\Uno.Extensions.Maui.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Navigation.Generators\\Uno.Extensions.Navigation.Generators.csproj",
"..\\..\\src\\Uno.Extensions.Navigation.Toolkit\\Uno.Extensions.Navigation.Toolkit.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Navigation.UI\\Uno.Extensions.Navigation.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Navigation\\Uno.Extensions.Navigation.csproj",
"..\\..\\src\\Uno.Extensions.Serialization\\Uno.Extensions.Serialization.csproj",
"..\\..\\src\\Uno.Extensions.Storage.UI\\Uno.Extensions.Storage.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Storage\\Uno.Extensions.Storage.csproj",
"..\\..\\src\\Uno.Extensions.Toolkit.UI\\Uno.Extensions.Toolkit.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Toolkit\\Uno.Extensions.Toolkit.csproj",
"..\\..\\src\\Uno.Extensions\\Uno.Extensions.csproj",
"..\\MauiProjects\\MauiApp1\\MauiApp1.csproj",
"..\\MauiProjects\\MauiControlsExternal\\MauiControlsExternal.csproj",
"MauiEmbedding.Mobile\\MauiEmbedding.Mobile.csproj",
"MauiEmbedding\\MauiEmbedding.csproj"
]
}
}
17 changes: 17 additions & 0 deletions samples/MauiEmbedding/MauiEmbedding.Base/AppHead.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<local:App x:Class="MauiEmbedding.AppHead"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wasm="http://platform.uno/wasm"
xmlns:local="using:MauiEmbedding"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="wasm">

<local:App.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///MauiEmbedding/AppResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</local:App.Resources>

</local:App>
28 changes: 28 additions & 0 deletions samples/MauiEmbedding/MauiEmbedding.Base/AppHead.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Microsoft.UI.Xaml;
using Uno.Resizetizer;

namespace MauiEmbedding;

public sealed partial class AppHead : App
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public AppHead()
{
this.InitializeComponent();
}

/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
base.OnLaunched(args);

MainWindow.SetWindowIcon();
}
}
Loading

0 comments on commit e20785c

Please sign in to comment.