Comandos
• Microsoft define la interfaz ICommand para proporcionar una abstracción de
comandos para sus frameworks XAML
public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
}
Edit
Command
CanExecute?
Execute(…)
Puede proporcionar un parámetro opcional (por lo
general con valor null) para que el comando trabaje
en un contexto específico
Los controles en .NET MAUI exponen una propiedad Command para la acción
principal de un control
Comandos en .NET MAUI
Menu Button ToolbarItem
• La inyección de dependencias (DI) es una técnica para desacoplar
los objetos y sus dependencias (o colaboradores).
• Sigue el Principio de Inversión de Dependencia: "los módulos de
alto nivel no deben depender de módulos de bajo nivel; ambos
deberían depender de abstracciones".
• Definición: es una forma en que un objeto (cliente) recibe otros
objetos (servicios) de los que depende. Lo que se “inyecta” es el
método o código que pasa el objeto de servicio al objeto de cliente
en tiempo de ejecución.
Dependency Injection
• Extraer las dependencias en interfaces y proporcionar
implementaciones de estas interfaces como parámetros también
es un ejemplo del patrón de diseño de la estrategia.
Dependency Injection
public interface IPlatformDiTestService
{
string SayYourPlatformName();
} public class PlatformDiTestService :
IPlatformDiTestService
{
public string SayYourPlatformName()
{
return "I am MacOS!";
}
}
• Nuestro código será más reutilizable, comprobable y mantenible, pues no
necesitamos saber y mantener cómo se implementan las dependencias.
• Se hace más flexible acceder a los objetos de servicio y de cliente.
Ventajas
La inyección de dependencias se puede hacer en la clase MauiProgram con el objeto builder
en el método CreateMauiApp:
Dependency Injection en .NET MAUI
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
builder.Services.AddSingleton<IPlatformDiTestService, PlatformDiTestService>();
builder.Services.AddTransient<MainPageViewModel>();
builder.Services.AddTransient<MainPage>();
return builder.Build();
}
.NET MAUI utiliza un contenedor de DI integrado.
Se pueden registrar:
• Interfaces (con su implementación)
• ViewModels
• Views
Ahora, en cualquier clase es posible acceder a alguno de los miembros registrados por
medio del constructor:
Consumo
public class MainPageViewModel : INotifyPropertyChanged
{
private readonly IPlatformDiTestService _platformDiTestService;
public MainPageViewModel(IPlatformDiTestService
platformDiTestService)
{
_platformDiTestService = platformDiTestService;
}
…
}
public partial class MainPage : ContentPage
{
public MainPage(MainPageViewModel
mainPageViewModel)
{
InitializeComponent();
this.BindingContext = mainPageViewModel;
}
…
• Transient: se crea una instancia de un objeto cada vez que se requiere una
referencia.
• Singleton: existe una única instancia global de un objeto en todo el ciclo de
vida de la app.
Tiempos de Vida de los servicios y opciones
de registro
Una aplicación .NET MAUI consta de páginas que contienen varios objetos de interfaz de usuario denominados vistas. Una de las tareas principales de la aplicación es mantener sincronizadas estas vistas y realizar un seguimiento de los distintos valores de acuerdo a la interacción de los usuarios.
Cuando la vista cambia, los datos subyacentes deben reflejar ese cambio y, de forma similar, cuando los datos subyacentes cambian, ese cambio debe reflejarse en la vista. Para controlar esto correctamente, se debe notificar a la aplicación los cambios en estas vistas o en los datos subyacentes.
La solución habitual consiste en definir eventos que indican cuándo se produce un cambio.
Después, se puede usar un manejador de eventos que recibe la notificación de estos cambios, y responde transfiriendo datos de un objeto a otro. Sin embargo, cuando hay muchas vistas, también debe haber muchos controladores de eventos, lo que da como resultado una gran cantidad de código que no se está reutilizando.
El enlace de datos automatiza esta tarea y elimina la necesidad de los controladores de eventos.
Al reemplazar el código de procedimientos en los controladores de eventos por código declarativo o marcado, la aplicación se simplifica y se aclara.
Por lo tanto, el enlace de datos es la técnica de vincular propiedades de dos objetos para que los cambios en una propiedad se reflejen automáticamente en la otra propiedad.
Típicamente, al menos uno de los 2 objetos suele ser un elemento de interfaz de usuario. Estos dos objetos se denominan el destino y el origen:
El destino es el objeto (y la propiedad) en la que se establece el enlace de datos.
El origen es el objeto (y la propiedad) al que hace referencia el enlace de datos.
En el caso más simple, los datos fluyen desde el origen al destino, lo que significa que el valor de la propiedad de destino se establece en el valor de la propiedad de origen. Pero en algunos casos, los datos también pueden fluir desde el destino al origen, o en ambas direcciones.
El enlace de datos se establece en el objeto de destino, que es el elemento Label.
La extensión de marcado x:Reference es necesaria para hacer referencia al objeto de origen, que es el elemento Slider denominado slider.
La extensión de marcado Binding enlaza la propiedad Rotation de Label a la propiedad Value de Slider.
Sin enlaces de datos, se establecería el evento ValueChanged del elemento Slider en un controlador de eventos que accede a la propiedad Value del elemento Slider y establece ese valor en la propiedad Rotation del elemento Label. El enlace de datos automatiza esta tarea, por lo que el controlador de eventos y el código que contiene ya no son necesarios.
extend the user interface and make it
responsive and reactive using MVVM or Model View View Model.
This architecture pattern is very popular when you're developing
applications with XAML because it enables a data binding,
a way for your user interface to respond to your code
behind and vice versa.
It's a way of managing your control and flow of data.
Your view just knows how to display data.
There's a button, there’s a label, there's an entry.
Your view model, you can think of it as code behind but
completely decoupled,
and what it is representing is what to display.
It may have a list of objects or strings and may know what to
do when a button is clicked
and it may know what to display in a label,
and the binding system inside
of.Net MAUI is what brings it all together,
enabling your UI to automatically update your
code behind and vice versa.
It handles not only properties back and forth,
but also events like those button clicks or swipe to deletes.
it connects everything from your view directly to the models and your services
When you integrate MVVM directly into
Yourapplication, you can be more productive
and abstract our code in a very nice, testable way.
There is an easier way to do all of this.
if you are using an MVVM framework,
Depending on the framework you're choosing, you
will get different features to either
write less boilerplate code.
That's kind of the goal for the most frameworks
you can do, view model to view model navigation.
Now there is the CommunityToolkit.Mvvm, which is
kind of like the spiritual successor of MVVMLight and
it's doing an amazing job. It relies on source generator.
So basically compile time. It will generate all the source things
for you that you don't need to write yourself. So it's C# code writing C#
code and it will make your life so much easier.
If we right-click and do Manage NuGet
packages, we can see
in the installed one we already have
the CommunityToolkit.Mvvm
It works for kind of like all C#
projects, all .NET projects.
Now here we are back at our BaseViewModel,
and I already mentioned it here, like for this IsBusy one we don't want
to write kind of like all this code, right?
So this is like 12 lines of code for each property
that we want to have. So that will be gigantic,
And what we can do now is basically
remove all of everything. And this needs to be
properties, right. So what we
want to do here is we can add some
attributes. Now here
we can say I want this to be an
ObservableProperty.
The same thing we can do for Title.
And now we have an ObservableProperty
Title.
It will generate all the properties for us. We
just need these backing fields right here
and we can generate the observable
properties from this. Now what else do we want to do?
What we also can do is say we want to
Make this a INotifyChangeFor
and we can mention the nameof(IsNotBusy).
So this is kind of like our little extra
thing that we have, like, hey we do want
to do OnPropertyChanged
for also the IsNotBusy. We just need to add this extra attribute
In fact, we can remove this whole
thing. We can remove both of these.
We don't need this anymore.
we just want to use this ObservableObject which has all
the things that I just removed basically. And in the BaseViewModel, we need
to make this partial because that’s the way how the
source generators work, it, of course, joins these classes.
It generates another partial class for the BaseViewModel to
actually generate all the code where he is busy and that kind of stuff.
So now it will be happy again our ObservableObject and we still
have all the same things here, right.
So if I run this again it will
still work as it did before, but now
we have a lot less code.
The other thing we need to do is create another property here.
This is going to be an Observable Collection
of type string and we’re going to call it Items.
Now, let's go ahead and bring that
in the system collections object model.
Again, we're also going to call this an ObservableProperty.
In the constructor, let’s create an instance of the ObservableCollection
Now the other thing that we need to do inside of
our view model is create an interaction.
Basically what we want to do is we want to be
able to tap this button and call a method.
What we're now going to do is we're going to create
something called a command.
Now, commands are actually built into.Net MAUI,
but you can also use a command
that is built into the MVVM Toolkit for.Net.
What we're going to do is we’re just going to go ahead and create
a method called Add, there we go.
What we want to do here is we want to add
our item and then we're going to
set the text property to string.empty.
So we just clear it out.
Now all we need to do is add another attribute called
RelayCommand (ICommand) to the top of it,
and RelayCommand is going to live inside of
the Community Toolkit MVVM input.
Just like we saw earlier,
if I pull over my source generators there's
ICommand and we can see that
this generated a bunch of code for us as well.
At the end of the day,
this is going to give us an eye relay command
and it's going to create a new command for us,
and what it's going to do is call the add event automatically.
This is really nice because if this was asynchronous,
it would automatically handle that for us back and forth,
and it's just really nice, tight code.
No hay cambios, es automáticamente detectado el nombre de las propiedades y sobre todo, comandos
Dependency injection,
gives you the architecture pattern of inversion of control, and specifically in .NET apps, constructor injection.
La inyección de dependencias es solo una forma en que un objeto (cliente) recibe otros objetos (servicios) de los que depende. Aquí, inyector significa el método o código que pasa el objeto de servicio al objeto de cliente. La inyección de dependencias es una versión del patrón de inversión de control. Aquí, la clase de servicio inyectará dependencias en un objeto en tiempo de ejecución.
Now, if you're coming from the asp.net core world,
dependency, injection it's built in.
And it now is with .NET MAUI, there is a dependency service that's built in in service provider.
All you have. To do is to register dependencies,
The .NET MAUI built-in DI also includes Constructor injection and automatic dependency resolution.
And this is the thing that developers
have really, really wanted when
it came to client development.
There's been frameworks that have
done this for a while, but now it's
built in to the box
And it's absolutely amazing.
A constructor injection it's a way of resolving thing.
Now there are specifically two types of dependencies that you can have
A Singleton, is like a global one instance, a single instance of an object
If you've created it once
and you want to get it again later,
then go ahead and retrieve that same reference.
And then you have a transient, and it is the opposite of a singleton
IT is a single instance every single time.
So every single time you new up a new one.
So based on what your application and where you're using these services, you're
either going to want a Singleton or
a transient