.NET MAUI Embedding - DevExpress .NET MAUI Controls
The controls from DevExpress .NET MAUI Controls can be used in an Uno Platform application via .NET MAUI Embedding.
Sample App
An existing sample app that showcases the controls is available here.
Installation
The DevExpress .NET MAUI Controls are currently available free of charge. However, in order to access the NuGet packages you do need to create an account at DevExpress website.
Once you have an account with DevExpress, you need to visit the Your DevExpress NuGet Feed URL page to retrieve a NuGet feed that's associated with your account. You can either add this as a NuGet feed in Visual Studio or use a nuget.config file.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="DevExpress Private Feed" value="[your NuGet feed goes here]" />
</packageSources>
</configuration>
Getting Started
Create a new application using the
unoapp
template, enabling .NET MAUI Embedding. In this case, we're going to use the Blank template (-preset blank
) and include .NET MAUI Embedding support (-maui
).dotnet new unoapp -preset blank -maui -o MauiEmbeddingApp
Remove the
net7.0
,net7.0-maccatalyst
and,net7.0-windows10.0.19041.0
target frameworks from both the MauiEmbeddingApp and MauiEmbeddingApp.MauiControls projects. Also, removenet7.0-maccatalyst
from the MauiEmbeddingApp.Mobile project, and remove the MauiEmbeddingApp.Windows project. The DevExpress .NET MAUI Controls only supports iOS and Android.Next, add a reference to
DevExpress.Maui.DataGrid
to the MauiEmbeddingApp.MauiControls project.In the
AppBuilderExtensions
class, onMauiEmbeddingApp.MauiControls
project, update theUseMauiControls
extension method to call theUseDevExpress
method.using DevExpress.Maui; namespace MauiEmbeddingApp; public static class AppBuilderExtensions { public static MauiAppBuilder UseMauiControls(this MauiAppBuilder builder) => builder .UseDevExpress() .ConfigureFonts(fonts => { fonts.AddFont("MauiEmbeddingApp/Assets/Fonts/OpenSansRegular.ttf", "OpenSansRegular"); fonts.AddFont("MauiEmbeddingApp/Assets/Fonts/OpenSansSemibold.ttf", "OpenSansSemibold"); }); }
Adding DataGridView Control
Update the EmbeddedControl.xaml in the
MauiEmbeddingApp.MauiControls
project with the following XAML that includes theDataGridView
control.<?xml version="1.0" encoding="utf-8" ?> <ContentView x:Class="MauiEmbeddingApp.MauiControls.EmbeddedControl" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:dxg="clr-namespace:DevExpress.Maui.DataGrid;assembly=DevExpress.Maui.DataGrid"> <dxg:DataGridView ItemsSource="{Binding Employees}"> <dxg:DataGridView.Columns> <dxg:TextColumn FieldName="Name" Caption="Name" /> <dxg:TextColumn FieldName="Position" Caption="Job"/> </dxg:DataGridView.Columns> </dxg:DataGridView> </ContentView>
Note
You may notice that the
Binding
markup extension is used on some properties. TheMauiEmbedding
can handle bindings between Maui Controls and UnoPlatform, just make sure the property in theBinding
expression matches the property on your ViewModel.Update the EmbeddedControl.xaml.cs with the following code.
namespace MauiEmbeddingApp.MauiControls; public partial class EmbeddedControl : ContentView { public EmbeddedControl() { InitializeComponent(); } }
It's time to create the ViewModel that will hold the properties that will be data bound to the
DataGridViewControl
control. InMauiEmbeddingApp
project, create a new folder calledViewModels
and add a new class calledMainViewModel
. This class will have the following code:namespace MauiEmbeddingApp.ViewModels; public class MainViewModel { public IReadOnlyList<Employee> Employees { get; }= new EmployeeData().Employees; }
And let's create the
Employee
model and mock it.public enum AccessLevel { Admin, User } public class Employee { public Employee(string name) { this.Name = name; } public string Name { get; } public DateTime BirthDate { get; set; } public DateTime HireDate { get; set; } public string? Position { get; set; } public string? Address { get; set; } public string? Phone { get; set; } public AccessLevel Access { get; set; } public bool OnVacation { get; set; } } public class EmployeeData { void GenerateEmployees() { ObservableCollection<Employee> result = new ObservableCollection<Employee>(); result.Add( new Employee("Nancy Davolio") { BirthDate = new DateTime(1978, 12, 8), HireDate = new DateTime(2005, 5, 1), Position = "Sales Representative", Address = "98122, 507 - 20th Ave. E. Apt. 2A, Seattle WA, USA", Phone = "(206) 555-9857", Access = AccessLevel.User, OnVacation = false } ); result.Add( new Employee("Andrew Fuller") { BirthDate = new DateTime(1965, 2, 19), HireDate = new DateTime(1992, 8, 14), Position = "Vice President, Sales", Address = "98401, 908 W. Capital Way, Tacoma WA, USA", Phone = "(206) 555-9482", Access = AccessLevel.Admin, OnVacation = false } ); result.Add( new Employee("Janet Leverling") { BirthDate = new DateTime(1985, 8, 30), HireDate = new DateTime(2002, 4, 1), Position = "Sales Representative", Address = "98033, 722 Moss Bay Blvd., Kirkland WA, USA", Phone = "(206) 555-3412", Access = AccessLevel.User, OnVacation = false } ); result.Add( new Employee("Margaret Peacock") { BirthDate = new DateTime(1973, 9, 19), HireDate = new DateTime(1993, 5, 3), Position = "Sales Representative", Address = "98052, 4110 Old Redmond Rd., Redmond WA, USA", Phone = "(206) 555-8122", Access = AccessLevel.User, OnVacation = false } ); result.Add( new Employee("Steven Buchanan") { BirthDate = new DateTime(1955, 3, 4), HireDate = new DateTime(1993, 10, 17), Position = "Sales Manager", Address = "SW1 8JR, 14 Garrett Hill, London, UK", Phone = "(71) 555-4848", Access = AccessLevel.User, OnVacation = true } ); result.Add( new Employee("Michael Suyama") { BirthDate = new DateTime(1981, 7, 2), HireDate = new DateTime(1999, 10, 17), Position = "Sales Representative", Address = "EC2 7JR, Coventry House Miner Rd., London, UK", Phone = "(71) 555-7773", Access = AccessLevel.User, OnVacation = false } ); result.Add( new Employee("Robert King") { BirthDate = new DateTime(1960, 5, 29), HireDate = new DateTime(1994, 1, 2), Position = "Sales Representative", Address = "RG1 9SP, Edgeham Hollow Winchester Way, London, UK", Phone = "(71) 555-5598", Access = AccessLevel.User, OnVacation = false } ); result.Add( new Employee("Laura Callahan") { BirthDate = new DateTime(1985, 1, 9), HireDate = new DateTime(2004, 3, 5), Position = "Inside Sales Coordinator", Address = "98105, 4726 - 11th Ave. N.E., Seattle WA, USA", Phone = "(206) 555-1189", Access = AccessLevel.User, OnVacation = true } ); result.Add( new Employee("Anne Dodsworth") { BirthDate = new DateTime(1980, 1, 27), HireDate = new DateTime(2004, 11, 15), Position = "Sales Representative", Address = "WG2 7LT, 7 Houndstooth Rd., London, UK", Phone = "(71) 555-4444", Access = AccessLevel.User, OnVacation = false } ); Employees = result; } public ObservableCollection<Employee> Employees { get; private set; } public EmployeeData() { GenerateEmployees(); } }
The final step is to add the
MainViewModel
as theDataContext
of theMainPage.xaml
file. The finalMainPage.xaml
file will look like this:<Page x:Class="MauiEmbeddingApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MauiEmbeddingApp.ViewModels" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Page.DataContext> <local:MainViewModel /> </Page.DataContext> <StackPanel> <embed:MauiHost xmlns:controls="using:MauiEmbeddingApp.MauiControls" xmlns:embed="using:Uno.Extensions.Maui" Source="controls:EmbeddedControl" /> </StackPanel> </Page>
Now the project is good to go! Press F5 and you should see the
DataGridView
control working as expected.
App Render Output
Android:
iOS: