Más novedades de .NET 6, PriorityQueue

Diría que es hasta sorprendente tras ver durante años diferentes implementaciones de PriorityQueue incluidas algunas usadas interamente en Frameworks de Microsoft, que nunca ha existido algo público directamente expuesto en .NET. Esto ha sido así hasta la llegada de .NET 6. En este artículo vamos a conocer las posibilidades de PriorityQueue.

Queue

Para explicar las novedades introducidas vamos a crear una pequeña clase que nos permita trabajar con personas.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Vamos a comenzar trabajando con Queue. Se trata de una estructura de datos genérica en la que los elementos se recuperan en el orden en que se añaden.

var persons = new Queue();

persons.Enqueue(new Person() { Name = "Javier" });
persons.Enqueue(new Person() { Name = "David" });
persons.Enqueue(new Person() { Name = "Pedro" });
persons.Enqueue(new Person() { Name = "Jesus" });

Vamos a utilizar el método TryDequeue que quita el elemento situado al principio y lo copia en el parámetro de salida.

while (persons.TryDequeue(out var person))
{
    Console.WriteLine($"{person.Name}");
}

La salida será algo como:

  • Javier
  • David
  • Pedro
  • Jesus

Justo lo que esperábamos y ya conocíamos, elementos ordenados obteniendo en cada momento el primero del principio de la colección.

Ahora imagina que quieres utilizar otro criterio para priorizar el orden en el que aparecen los elementos, independientemente del orden en que se pongan en cola.

Digamos que en nuestro ejemplo, cada persona tiene una edad y queremos ordenar usando ese criterio.

PriorityQueue

Podemos usar la nueva clase PriorityQueue con ese objetivo, usar otro criterio para priorizar.

Añadimos varias personas a un PriorityQueue:

var prioritizedAgents = new PriorityQueue();

prioritizedAgents.Enqueue(new Person() { Name = "Javier" }, 36);
prioritizedAgents.Enqueue(new Person() { Name = "David" }, 45);
prioritizedAgents.Enqueue(new Person() { Name = "Pedro" }, 41); 
prioritizedAgents.Enqueue(new Person() { Name = "Jesus" }, 33);

Como podemos ver en el ejemplo anterior, se especifica el tipo a añadir en la cola y un segundo tipo, que se usarará para la priorización.

En nuestro caso, tenemos una cola de personas y la prioridad es la edad donde se usa un int.

while (prioritizedAgents.TryDequeue(out var person, out var age))
{
    Console.WriteLine($"{person.Name}, age {age}");
}

¿Cuál es el resultado?

  • Jesus, age 33
  • Javier, age 36
  • Pedro, age 41
  • David, age 45

Las personas ordenadas por edad. Hay que tener en cuenta el orden relativo a como se añadieron a la cola. Al priorizar,un valor más bajo otorga una prioridad más alta.

Por supuesto, el tipo utilizado para definir la prioridad no tiene que ser un número; puede ser cualquier cosa que implemente IComparer.

Estamos ante una novedad excelente para problemas en los que las estructuras de datos se procesan según el orden y además otro parámetro que otorga prioridad.

Más información

[C# 10] Const Interpolated Strings

Continuamos hablando de novedades de C# 10. En esta ocasión hablaremos de cadenas interpoladas constantes, nueva funcionalidad que llega para hacer que nuestro código sea más legible y más conciso.

Concatenar cadenas constantes hasta ahora

Cuando usamos cadenas constantes en C# 9.0 y versiones anteriores, solo podíamos concatenarlas usando el operador +:

const string Scheme = "https"; 
const string Home = "home";

const string Environment = Scheme + "://localhost:5002";const string HomeUri = Environment + "/" + Home;

Nuevas posibilidades

Con la llegada de C# 10, ahora podemos usar el operador de cadena interpolada $ para combinar cadenas constantes:

const string Scheme = "https"; 
const string Home = "home";

const string Environment = $"{Scheme}://localhost:5002";
const string HomeUri = $"{Environment}/{Home}";

NOTA: Es importante tener en cuenta acerca de esta función es que solo funciona si todas las cadenas utilizadas en la cadena interpolada están marcadas const.

¿Qué te parece este añadido?. Recuerda que puedes usar los comentarios de la entrada para dejar tu feedback.

Más información

[C# 10] File Scoped Namespaces

Seguimos repasando novedades de C# 10. En esta ocasión, vamos a centrarnos en File Scoped Namespaces.

Declaración normal de namespaces (hasta ahora)

Imagina que creamos una clase Person.cs con el siguiente contenido.

using System;

namespace FileScopedNamespaceSample
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

La clase Person.cs se encuentra en el namespace FileScopedNamespaceSample. Cuando se observa el fragmento de código anterior, se puede ver que la declaración del espacio de nombres normal necesita un par de corchetes.

¿Y si pudiesemos simplificar esto?.

File Scoped Namespaces

A continuación, veremos un fragmento de código que muestra una declaración de espacio de nombres de ámbito de archivo (File Scoped Namespace) que es posible con C# 10.

using System;

namespace FileScopedNamespaceSample;
    
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Como puedes ver, después del espacio de nombres se agrega un punto y coma, y no corchetes como con una declaración de espacio de nombres clásica. Este espacio de nombres de ámbito de archivo significa que todos los tipos de este archivo, como clases e interfaces, están en el espacio de nombres FileScopedNamespaceSample.

Es posible igualmente colocar la declaración del espacio de nombres en la parte superior del archivo, encima de la directivas using.

namespace FileScopedNamespaceSample;
   
using System;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Pero no es posible colocar la declaración del namespace al final del archivo.

También es importante destacar que solo podemos declarar un espacio de nombres de ámbito de archivo por archivo. Por lo general, la mayoría de las clases C# tienen solo un espacio de nombres, por lo que no hay problema.

Pero, ¿qué sucede si deseas declarar más de un espacio de nombres en un solo archivo?.

Esto no es algo posible con espacios de nombres de ámbito de archivo. Si intentas agregar otro espacio de nombres con ámbito de archivo en el mismo archivo, obtendrás un error en el IDE.

Los espacios de nombres de ámbito de archivo son una nueva posibilidad pequeña, pero interesante y útiles en diferentes casos.

¿Qué te parece esta nueva funcionalidad?. Recuerda, puedes usar los comentarios de la entrada para dejar tu feedback.

Más información

[C# 10] Global Usings

Una de las novedades más sonadas quizás por ser un cambio del que estoy seguro tendrá desarrolladores a favor y otros en contra. En este artículo, vamos a hablar de la llegada de Global Usings.

Declarar usings hasta ahora

En la parte superior de todas las clases C# hay una colección de instrucciones using que especifican los espacios de nombres que la clase necesita para compilar:

using System;

namespace GlobalUsingsSample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Global Usings!");
        }
    }
}

Cuando en el mismo proyecto tenemos diferentes clases haciendo uso de las mismas APIs, aparecen duplicadas instrucciones using.

Es cierto que Visual Studio puede colapsar los usings, pero, ¿y si se pueden gestionar de otra forma?.

Global Usings

C # 10 permite hacer uso de la palabra global para poder identificar namespaces que deberían aplicarse a toda nuestra aplicación:

global using System;

// The previous using statements will be included in every class in this project.

Estas declaraciones pueden colocarse en un archivo en cualquier lugar del proyecto, y el compilador de C# sabrá que tiene que aplicar estos namespaces a nivel de aplicación.

De esta forma:

namespace GlobalUsingsSample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Global Usings!");
        }
    }
}

No hay namespaces a nivel de la clase!. Pero…¿y si añades un namespace a nivel de clase que ya se encuentra a nivel global?. Visual Studio avisará de este caso con un warning.

Más información

Calendario común de comunidades .NET de España

¿Y si en un lugar centralizado y común pudieramos ver de un vistazo todos los eventos de tecnologías .NET que hay en España?. Esta es la idea principal de la que quiero hablaros hoy en este artículo.

El origen

Hablar con otros de tecnología, proyectos e ideas es algo de lo que personalmente disfruto mucho. Poder ayudar a otros, crecer entre todos es genial. Y en ocasiones, nacen buenas ideas. En una de estas conversaciones con Marcelo Villacorta en la comunidad .NET de Sevilla salía esta idea "estaría genial poder sincronizarnos entre todas las comunidades, saber de forma fácil que eventos existen, etc".

Idea

Esta idea fue planteada en una reunión periódica que se tiene tiene entre toda la comunidad (bueno, con representates de cada una de las comunidades .NET de España) recibiendo muy buena aceptación!.

La implementación

Tras aterrizar algunas ideas, me complace poder compartir el calendario común de las comunidades .NET de España.

Se trata de una página web donde se sincronizan de forma automática cada día los eventos de cada una de las comunidades .NET de España. La sincronización obtiene cada día los nuevos eventos (o los eventos existentes si se han editado) utilizando las APIs de Meetup y eventbrite.

Con posibilidad de poder hacer búsquedas, exportar los eventos a tu propio calendario así como poder visualizar la información en diferentes modos como vista semanal, mensual, en un listado, etc., la página tiene como objetivos:

  • Facilitar la visualización de todos los eventos de la comunidad de forma sencilla de modo que ayude tanto a evitar eventos en el mismo día y hora (siempre y cuando sea posible) así como ayudar a dar visibilidad de eventos entre todos.
  • Tener una herramienta más para obtener información de forma sencilla. ¿Cuál es el mes con más eventos?, ¿cuantos eventos se celebraron en todo un año?, etc.
  • En definitiva, ayudar a actuar más como UNA gran comunidad, un bloque común aunque haya distancia separando algunos grupos de usuario de otros.

Calendario .NET

Necesitamos tu ayuda!

El requisito para cada comunidad es sencillo, sólo necesitamos registrar su comunidad (página web a la misma) en el calendario para que comience la sincronización!. Si tu comunidad no esta entre el listado de comunidades actualmente incluidas, puedes añadirla enviando una Pull Request en este repositorio.

Se trata de un proyecto por y para la comunidad así que cada paso importante deberíamos darlo entre todos juntos. Uno de estos primeros pasos es… el nombre. Tener un nombre, una marca reconocible es importante. Al fin y al cabo es lo que todos usaremos para navegar a su dominio, usaremos este nombre al referirnos al calendario, etc. Para este tipo de decisiones usaremos Issues de GitHub. Puedes encontrar la Issue donde poder aportar tu idea para el nombre aquí.

Más información

Borders personalizados en .NET MAUI

Aplicar bordes personalizados es una necesidad bastante común utilizada en el diseño de aplicaciones para crear estructuras visuales concretas, resaltar elementos o poder personalizar ciertos controles específicos.

En Xamarin.Forms el control Frame ha sido ampliamente utilizado con este fin. Sin embargo, el control Frame contaba con ciertas limitaciones:

  • No poder personalizar cada esquina del borde.
  • No poder personalizar el ancho del borde.
  • No poder utilizar brushes en el propio borde.
  • Etc.

Con la Preview 9 de .NET MAUI llega un nuevo control, Border, con bastantes más posibilidades y con el objetivo de resolver todas las limitaciones que teníamos hasta ahora. ¿Lo revisamos en este artículo?.

Nuevo control Border

El nuevo control Border, similar en concepto al Frame, es un control que permite un único elemento como contenido pero que puede ser cualquier cosa. Es decir, podremos aplicar un Border desde a un sencillo Label a un Grid con un layout complejo.

<Border Stroke="Red" StrokeThickness="2">
    <Border.ShapeBorder>
        <RoundRectangle CornerRadius="12, 0, 0, 24" />
    </Border.ShapeBorder>
    <Label Text="Border" />
</Border>

El control Border cuenta con diferentes propiedades para personalizar el borde:

  • Stroke: Brush que define el color o gradiente a utilizar en el borde.
  • StrokeThickness: Grosor del borde.
  • StrokeDashArray: Se utiliza una colección de valores Double que indican el patrón Dash y los espacios que se usan para delinear la figura a utilizar en el borde.
  • StrokeDashOffset: Es un valor de tipo Double que indica la distancia a usar en el patrón Dash desde donde comienza.
  • StrokeLineJoin: Especifica como se realizará la unión entre los vértices de la figura a utilizar en el borde.
  • StrokeLineCap: Especifica como es el trazo del inicio y fin de la figura a utilizar en el borde.

Y entre las propiedades disponibles me gustaría destacar, StrokeShape. Espera un Shape que define la forma del borde. Por defecto se usa un Rectángulo pero puede ser desde un Rectángulo con bordes redondeados a cualquier figura.

Podemos pasar de un borde con forma rectangular y bordes redondeados personalizados:

<Border Stroke="Red" StrokeThickness="2">
    <Border.ShapeBorder>
        <RoundRectangle CornerRadius="12, 0, 0, 24" />
    </Border.ShapeBorder>
    <Label Text="Border" />
</Border>

A una elipse:

<Border Stroke="Red" StrokeThickness="2">
    <Border.ShapeBorder>
        <Ellipse />
    </Border.ShapeBorder>
    <Label Text="Border" />
</Border>

A continuación, veamos como funcionan estas propiedades en conjunto en un ejemplo de forma visual.

.NET MAUI Border

¿Qué te parece esta novedad en .NET MAUI?. Recuerda, puedes usar los comentarios de la entrada para dejar tu feedback.

Más información

Sombras en .NET MAUI

La sombra es una de las formas en que un usuario percibe la elevación. Este efecto de elevación transmite en qué debe centrarse el usuario. Y esta es la razón por la que los diseñadores móviles prefieren incorporar sombras en sus diseños.

Con la llegada de la Preview 9 de .NET MAUI obtenemos novedades a nivel de UI como el nuevo control Border o una nueva API para poder crear sombras. En este artículo, vamos a centrarnos en conocer la nueva API de sombras.

Sombras

Sombras

A nivel de View, es decir, en cualquier vista disponible en .NET MAUI, se pueden añadir sombras. Esto quiere decir que se pueden añadir sombras desde en imágenes a cualquier Shape y por supuesto en un Button o Label.

Contamos con una nueva propiedad llamada Shadow de tipo Shadow. Shadow es un Element que cuenta con las siguientes propiedades:

  • Radius: Es el radio del Gaussian blur usado para generar la sombra.
  • Color: El color de la sombra.
  • Offset: Offset de la sombra en relación al elemento visual donde se adjunta la misma.
  • Opacity: La opacidad de la sombra.

La forma más sencilla de añadir una sombra es:

<Label Text="Label">
    <Label.Shadow>
        <Shadow 
            Color="Blue"
            Offset="10, 20"
            Offset="0.5"
            Radius="12">
    </Label.Shadow>
</Label>

NOTA: Cada propiedad que tenemos disponible en la clase Shadow es una BindableProperty por lo tanto, podemos actualizar cada propiedad con bindings.

Podemos crear sombras como recursos compartidos y utilizar la misma sombra en diferentes elementos visuales:

<ContentPage.Resources>
    <ResourceDictionary>

        <Shadow x:Key="Shadow" Brush="Red" Offset="12, 12" Radius="12" />

    </ResourceDictionary>
</ContentPage.Resources>

<Ellipse HeightRequest="100" WidthRequest="100" Fill="Blue" Shadow="{StaticResource Shadow}" />
<Button Text="Button" BackgroundColor="Blue" Shadow="{StaticResource Shadow}" />

Sombras en .NET MAUI

¿Qué te parece esta novedad en .NET MAUI?. Recuerda, puedes usar los comentarios de la entrada para dejar tu feedback.

Más información

.NET MAUI Preview 5

Vaya, no hace tanto del //Build donde se lanzo la Preview 4 y ya tenemos disponible la nueva Preview 5. Se continua con progreso release a release en todas las áreas (implementaciones en el framework, novedades en el framework, proyecto único, tooling, etc). En esta versión tenemos novedades jugosas cómo la llegada de Shell, animaciones o el proyecto único.

En este artículo, vamos a hacer un repaso a todas las novedades principales.

Novedades en controles

Se sigue el proceso de creación de Handlers (recuerda, es la nueva arquitectura para la creación de los controles nativos desde la abstracción) con más controles 100% completados (ActivityIndicator, CheckBox, Image, Slider, Stepper) y varios más completos.

Más y más controles!

Disponible transformaciones y animaciones

Se ha añadido implementación para todas las propiedades que permiten aplicar transformaciones a un control (rotar, escalar, etc). De igual forma, se añade soporte a animaciones en controles de .NET MAUI.

Animaciones!

Tanto el aplicar transformaciones, como el uso de animaciones mantiene la misma API de Xamarin.Forms:

view.FadeTo(1, 800);

Así que, si conocías la API o tenías código relacionado con animaciones, podrás portar código así como reutilizar tanto código como conocimientos en .NET MAUI.

Novedades en Proyecto único

Si habías probado el proyecto único, verías que todo estaba unificado en un único proyecto para Android, iOS y macOS pero teníamos otros dos proyectos para WinUI. Ahora, con la Preview 5, al realizar:

dotnet new maui

Se creará una solución con dos proyectos, uno haciendo uso de multi targeting para la mayoría de plataformas, y otro para WinUI. Esto es otro paso adelante en el concepto de proyecto único y sobretodo evitará muchas confusiones acerca de qué proyecto usar para lanzar la App en Windows haciendo uso de WinUI.

NOTA: Para poder tener soporte a esta nueva estructura de proyectos, necesitas tener instalado las extensiones de Visual Studio Project Reunion 0.8 (Preview).

Disponible en NuGet

Por primera vez no es necesario añadir unas fuentes de NuGet disponibles porque .NET MAUI ya esta disponible en nuget.org.

nuget.org

Primera documentación disponible!

En esta Preview es donde recibimos también la primera documentación oficial disponible en https://docs.microsoft.com/es-es/dotnet/maui/

Documentación

Visual Studio 2020 Preview 1

Junto con la Preview 5 de .NET 6 llega la primera Preview de Visual Studio 2022!.

Primera Preview de Visual Studio 2022

Con soporte a 64 bits, mejoras de rendimiento, mejoras en IntelliCode y bastantes más novedades, también añade soporte a desarrollo móvil.

NOTA: Si desarrollas con .NET MAUI, por ahora deshabilita XAML Hot Reload para evitar errores (en desarrollo).

Más información

Contribuir a .NET MAUI

.NET MAUI es un proyecto Open Source desde su inicio y desde etapas tempranas, se permite colaborar o contribuir de diferentes formas (eso sí, con unas bases a seguir bastante definidas).

.NET MAUI

Tras ver ya algunas contribuciones de la comunidad, y recibir un correo preguntando como se puede ayudar, en este artículo, voy a hacer un repaso en las diferentes formas en las que se puede contribuir en .NET MAUI, así como compilar el proyecto, etc.

¿Te interesa?. Vamos a por ello!.

Consejos antes de comenzar

Antes de empezar, colaborar en proyectos Open Source tiene partes positivas como:

  • Vas a ayudar a otros!.
  • Es una forma divertida de aprender.
  • Etc.

Sin embargo, si nunca has colaborado antes probablemente tengas algunas dudas. La primera de ellas será como hacerlo. Para eso espero que este artículo sea de ayuda. El segundo de los posibles problemas esta en el conocido “síndrome del impostor”. Dudas si lo que haces es correcto,  etc. En este punto, no te preocupes!. Si hay algo que se pueda mejorar, lo verás en el feedback. Es parte de la “gracia” de colaborar así, aprenderás posiblemente cosas nuevas.

Tan solo recuerda:

  • No tengas dudas. Aprenderás cosas nuevas como yo y todos lo hacemos a diario.
  • Puedes preguntar al crear la PR lo que necesites!.

Formas de contribuir

Lo primero de todo, contribuir tiene varias definiciones aunque en este caso:

“se trata de ayudar y concurrir con otros al logro de un cierto fin”

Se puede ayudar de muchas formas!. No tienes porque implementar la espectacular funcionalidad X para poder contribuir.

Vamos a repasar las diferentes opciones disponibles:

  • Probar las Previews.
  • Dar tu feedback en las Specs de nueva funcionalidad.
  • Correcciones en la wiki.
  • Tomar una de las issues disponibles (implementar una propiedad en un Handler).

Preparar el entorno

Antes de comenzar a trabajar con .NET MAUI, para trabajar con .NET 6, debemos instalar .NET 6 y otros requisitos.

Comenzamos instalando la Preview de .NET 6:

Para trabajar con .NET para Android y iOS necesitarás instalar también los workloads:

Android:

iOS:

En el caso de querer probar la implementación de macOS usando Catalyst, necesitas instalar:

Para compilar el proyecto debemos comenzar por tener el mismo. Es sencillo:

git clone https://github.com/dotnet/maui.git C:\maui

Usando Visual Studio (Windows o macOS), tras obtener el proyecto no deberás hacer nada especial para compilarlo. Abre la solución Microsoft.Maui.sln y pulsa F5.

Estructura del proyecto

A continuación, vamos a ver la estructura básica de la solución. Con respecto a Xamarin.Forms, se simplifica considerablemente el número de proyectos (gracias al uso de Multitargeting) donde:

  • En la carpeta Controls puedes encontrar los Renderers de Xamarin.Forms y otras partes usadas por el paquete Compatibility.
  • En Core, esta disponible el proyecto Core de .NET MAUI. En este proyecto puedes encontrar los Handlers en la carpeta Handlers y es el proyecto principal que editarás. Dentro de esta carpeta también puedes encontrar los proyectos de tests relacionados con el Core de .NET MAUI.
  • En la carpeta Essentials se encuentra la evolución de Xamarin.Essentials.
  • Todo lo que permite funcionar a al proyecto único o Single Project se encuentra en la carpeta SingleProject.

Implementar una propiedad de un handler

Has revisado las issues de .NET MAUI y te has decidido a colaborar implementando una propiedad de un Handler. Fantástico!. A continuación, algunos detalles que debes tener en cuenta:

  • Como la propia issue indica, añade una sola propiedad para un control.
  • Debes implementar el método del Handler para iOS y Android.
  • Crea los métodos de extensión necesarios o reutiliza lo existentes cuando sea apropiado / posible.
  • Mueve el código del Renderer correspondiente que encontrarás en la carpeta Compatbility. Marca el código portado con el atributo [PortHandler].
  • Añade tests tanto para iOS como para Android (DeviceTests).
  • Evitar cualquier cambio que no sea esencial para la propiedad del Handler (incluidos los espacios en blanco).

Crea una nueva rama partiendo de lo último disponible en main.

No se requiere cumplir un patrón específico a la hora de crear la rama. Mis recomendaciones serían:

  • Puedes crear una rama “fix-{id}” donde el id es el identificador de la Issue.
  • Puedes usar un nombre descriptivo. Por ejemplo, si estas corrigiendo un error al seleccionar un elemento en el TabView podría ser algo como “implement-text-button”.
  • También puedes usar una combinación de las ideas anteriores. Por ejemplo: “fix-1234-text-button”.

El momento de enviar la PR

Añade un título descriptivo junto con una breve descripción. Añade el enlace a la issue asociada.

Todo listo para enviar!. Una vez enviado, miembros del equipo comenzarán a revisar todo. Una vez pasadas revisiones, builds y otras validaciones. Enhorabuena, tus cambios estarán incluidos en .NET MAUI!.

Hasta aquí. Creo que hemos realizado un buen resumen de como contribuir en .NET MAUI. Además de todo lo expuesto, si puedo ayudar en algo tan solo avísame. Cualquier feedback es bienvenido en los comentarios de la entrada!.

Más información

.NET MAUI Preview 2

Con la primera Preview de .NET 6 llegaban los primeros bits para poder hacer pruebas con .NET para Android y iOS, una primera muestra de todo lo que llegará con .NET MAUI. Con la Preview 2, llegan muchas más novedades relacionadas con .NET MAUI como:

  • Primera muestra de proyecto único. Incluye gestión común de iconos, fuentes, etc.
  • Introducción del concepto de nueva aplicación, ventana etc.
  • Handlers. Son la evolución de los actuales renderers en Xamarin.Forms, pero con una nueva arquitectura en búsqueda de mayor rendimiento y opciones de extensibilidad.
  • HostBuilder.
  • Soporte a Mac Catalyst.

En este artículo, vamos a hacer un repaso a todo lo que incluye la Preview 2, además de repasar que nos esperar en próximas Previews.

¿Qué es .NET MAUI?

Partiendo de la evolución de Xamarin.Forms llega a .NET, Multi-platform App UI, MAUI. Se trata de un framework, evolución de Xamarin.Forms, que permitirá crear interfaces de usuario nativas para escritorio y dispositivos móviles usando una base de código común y un único proyecto.

.NET MAUI

Las claves de MAUI son:

  • Interfaz de usuario multi-plataforma nativa.
  • Evolución de Xamarin.Forms.
  • Base de código común, un único proyecto.
  • .NET 6.
  • Soporte oficial para Android, iOS, macOS y Windows.

Los objetivos fundamentales son:

  • Mejorar el rendimiento.
  • Mejorar las posibilidades a la hora de extender controles. Extender de forma más sencilla.
  • Habilitar otras opciones como Model-View-Update (MVU).

Puedes verlo todo con más detalles en el siguiente video:

Preparar el entorno

Antes de comenzar a trabajar con .NET MAUI, necesitamos instalar .NET 6 y otros requisitos. Y antes de instalar nada, recuerda que vamos a instalar Previews. NO están listos para producción, el objetivo principal es permitir comenzar a probar y descubrir las novedades, etc.

Comenzamos instalando la Preview de .NET 6:

Para trabajar con .NET para Android y iOS necesitarás instalar también los workloads:

Android:

iOS:

En el caso de querer probar la implementación de macOS usando Catalyst, necesitas instalar:

Casi lo tenemos todo listo!. Puedes obtener algunos ejemplos usando .NET 6 preparados aquí.

Con .NET 6 ganamos la línea de comandos para poder realizar compilaciones y despliegues de aplicaciones móviles. Puedes compilar aplicaciones .NET MAUI con el comando:

dotnet build HelloMaui

Y compilar y desplegar a la vez usando:

dotnet build HelloMaui -t:Run -f net6.0-android

NOTA: En esta Preview debes añadir también –no-restore. Es debido a algo que estará implementado en la próxima Release, pero no disponible en esta.

Para lanzar un proyecto .NET MAUI, necesitas especificar el $(TargetFramework) usando el parámetro -f.

Hola .NET MAUI

Pero…te estarás preguntando si puedes usar algún IDE. Actualmente hay soporte a Visual Studio 16.9 para Windows pero hay que hacer unos pequeños cambios.

NOTA: El soporte a Visual Studio para macOS o Visual Studio Code aún no esta disponible.

Abre una línea de comandos para activar el EnableWorkloadResolver.sentinel:

cd "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\SdkResolvers\Microsoft.DotNet.MSBuildSdkResolver"
type NUL > EnableWorkloadResolver.sentinel

Debes reiniciar Visual Studio (si lo tenías abierto) tras este cambio.

.NET MAUI Preview 2

A continuación, veamos que incluye esta Preview así como que podemos hacer con ella.

Proyecto único

Simplificar y reducir conceptos necesarios para ser productivos es uno de los objetivos de .NET MAUI. Una de las formas de buscar este objetivos es con el proyecto único. A diferencia de Xamarin.Forms donde teníamos una librería común compartida junto con un proyecto nativo por cada plataforma, en .NET MAUI tenemos un proyecto único para todas las plataformas.

Proyecto único

En estos momentos, el proyecto incluye soporte a Android, iOS y macOS. El soporte a Windows usando WinUI 3 llegará en próximas Previews.

Para poder usar un proyecto único con diferentes plataformas donde cada una requiere recursos como imágenes o fuentes, necesitamos una forma común de gestionar recursos. Las fuentes e imágenes se pueden colocar en una ubicación común de la solución y .NET MAUI lo gestionará para adaptar todos los recursos a cada plataforma nativa. Estos recursos se registran en el *.csproj como SharedImage y SharedFont.

<ItemGroup>
    <SharedImage Include="appicon.svg" ForegroundFile="appiconfg.svg" IsAppIcon="true" />
    <SharedFont Include="Resources\Fonts\ionicons.ttf" />
</ItemGroup>

Android, iOS y macOS (Catalyst)

El soporte a macOS en .NET MAUI utiliza Catalyst. Para poder usar Catalyst y compilar la aplicación para escritorio, se necesita usar el siguiente TargetFramework:

<TargetFrameworks>net6.0-android;net6.0-ios</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">$(TargetFrameworks);net6.0-maccatalyst</TargetFrameworks>

Handlers

La evolución de los Renderers de Xamarin.Forms. Se busca tener siempre el equivalente a un Fast Renderer (solo crear el elemento nativo necesario sin ningún elemento padre o similar para realizar tareas de posicionamiento, reduciendo el árbol visual y por consiguiente, consiguiendo un mejor rendimiento), además de realizar una gestión más óptima con Layouts, etc.

En esta Preview se ha incluido un subconjunto de Handlers (controles) entre los que puedes encontrar: Label, Button, Entry, Slider y Switch. Sin embargo, en esta Preview también se incluye la librería Compatibility.

¿Qué es el paquete Compatibility?

Dado que .NET MAUI es una evolución de Xamarin.Forms, se busca desde el inicio de .NET MAUI ofrecer una experiencia de conversión de proyectos sencilla. Para permitir seguir usando Custom Renderers y otras opciones creadas con Xamarin.Forms, se ha creado el paquete Compatibility. De igual forma, se pueden usar Renderers (controles) de Xamarin.Forms en .NET MAUI. Por ese motivo, aunque no este disponible el Handler de Image (por ejemplo), puedes usar imágenes también.

NOTA: Existe una diferencia de rendimiento entre Renderers y Handlers, sin embargo, poder rehusar grandes cantidades de código gracias al paquete Compatibility, es un gran beneficio.

BuildHost

Se añade en .NET MAUI el concepto de Host, junto con extensiones para configurar servicios, fuentes o habilitar el uso de Renderers para migrar proyectos de Xamarin.Forms. Este nuevo patrón también presenta un lugar único y coherente para que los autores de librerías se integren con .NET MAUI.

public class Application : MauiApp
{
    public override IAppHostBuilder CreateBuilder() => 
        base.CreateBuilder()
            .RegisterCompatibilityRenderers()
            .ConfigureServices((ctx, services) =>
            {
                services.AddTransient<MainPage>();
                services.AddTransient<IWindow, MainWindow>();
            })
            .ConfigureFonts((hostingContext, fonts) =>
            {
                fonts.AddFont("ionicons.ttf", "IonIcons");
            });

    public override IWindow CreateWindow(IActivationState state)
    {
        Microsoft.Maui.Controls.Compatibility.Forms.Init(state);
        return Services.GetService<IWindow>();
    }
}

Otras novedades

  • Xamarin.Essentials también esta integrado en esta Preview. Essentials y toda su funcionalidad es ahora parte directa del framework.
  • AndroidX esta ya integrado en .NET 6.
  • Funciona el Build Host para conectar desde Windows a un Mac.
  • Añadido soporte a AOT para iOS en .NET 6.
  • Etc.

¿Qué es lo próximo?

Habrá varias Previews antes de la llegada de .NET 6 y .NET MAUI en Noviembre. La próxima Preview contará además de con mas Handlers (controles), primera versión de nuevo sistema de Layout, concepto de Startup, eventos de ciclo de vida, y mucho más. Al estar disponible, volveremos a tener artículo en el blog así como algún streaming en Twitch.

¿Qué te parece lo que ves en la Preview?, ¿cuál es tu novedad favorita?. Puedes dejar cualquier feedback o pregunta en los comentarios de la entrada!

Más información