> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-9-la-construccion.-navegacion-y-configuracion-de-usuario/messenger.md).

# Messenger

En el desarrollo de aplicaciones siguiendo el patrón **MVVM**, la comunicación entre diferentes componentes (como *ViewModels*) es esencial para mantener una arquitectura limpia y desacoplada. Uno de los desafíos más comunes es cómo notificar a una vista o *ViewModel* sobre cambios realizados en otra parte de la aplicación sin crear dependencias directas entre ellos. Aquí es donde entra en juego el patrón **Messenger**, basado en el patrón *publicador/suscriptor* (*Publisher/Subscriber*).

## ¿Qué es el Patrón Messenger?

El **patrón Messenger** es una implementación del patrón *publicador/suscriptor* que facilita la comunicación entre componentes de una aplicación sin que estos necesiten conocerse directamente. Este patrón permite que un *ViewModel* publique mensajes que otros *ViewModels* puedan suscribirse para recibir notificaciones y actuar en consecuencia.

## Beneficios del Uso del Messenger

* **Desacoplamiento:** Los componentes no necesitan referencias directas entre sí, lo que facilita el mantenimiento y la escalabilidad.
* **Flexibilidad:** Permite una comunicación bidireccional y muchos-a-muchos entre *ViewModels*.
* **Reusabilidad:** Los mensajes pueden ser reutilizados en diferentes partes de la aplicación.

## Implementación del Messenger

Aunque existen librerías como **MVVM Light** que proporcionan implementaciones robustas del patrón Messenger, también es posible crear una versión personalizada sencilla. A continuación, se muestra cómo implementar un Messenger básico en una aplicación UWP siguiendo el patrón **MVVM**.

### Paso 1: Crear la Clase Messenger

Primero, definimos una clase `Messenger` que manejará la suscripción y publicación de mensajes.

```csharp
public class Messenger
{
    private static Messenger _instance;
    public static Messenger Instance => _instance ?? (_instance = new Messenger());

    private readonly Dictionary<Type, List<Action<object>>> _subscribers = new Dictionary<Type, List<Action<object>>>();

    // Método para suscribirse a un tipo de mensaje específico
    public void Subscribe<TMessage>(Action<TMessage> action)
    {
        var messageType = typeof(TMessage);
        if (!_subscribers.ContainsKey(messageType))
        {
            _subscribers[messageType] = new List<Action<object>>();
        }
        _subscribers[messageType].Add(o => action((TMessage)o));
    }

    // Método para publicar un mensaje
    public void Publish<TMessage>(TMessage message)
    {
        var messageType = typeof(TMessage);
        if (_subscribers.ContainsKey(messageType))
        {
            foreach (var action in _subscribers[messageType])
            {
                action(message);
            }
        }
    }
}
```

### Paso 2: Definir los Tipos de Mensajes

Es recomendable definir clases para cada tipo de mensaje que se va a enviar. Por ejemplo, para notificar que un proyecto ha sido actualizado:

```csharp
public class ProjectUpdatedMessage
{
    public int ProjectId { get; set; }
    public string ProjectName { get; set; }
    // Otras propiedades relevantes
}
```

### Paso 3: Publicar Mensajes desde el ViewModel de Edición o Detalle

Cuando se actualiza un proyecto desde la vista de edición o detalle, el *ViewModel* correspondiente debe publicar un mensaje para notificar a otros componentes sobre el cambio.

```csharp
public class EditProjectViewModel : INotifyPropertyChanged
{
    // Propiedades y comandos del ViewModel

    private void UpdateProject()
    {
        // Lógica para actualizar el proyecto

        // Publicar el mensaje de actualización
        var message = new ProjectUpdatedMessage
        {
            ProjectId = this.ProjectId,
            ProjectName = this.ProjectName
            // Asignar otras propiedades según sea necesario
        };
        Messenger.Instance.Publish(message);
    }

    // Implementación de INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
```

### Paso 4: Suscribirse a los Mensajes en el ViewModel de la MainPage

El *ViewModel* de la `MainPage` debe suscribirse a los mensajes publicados para poder actualizar la interfaz de usuario en respuesta a los cambios.

```csharp
public class MainViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Project> Projects { get; set; }

    public MainViewModel()
    {
        Projects = new ObservableCollection<Project>();
        // Suscribirse al mensaje de actualización de proyectos
        Messenger.Instance.Subscribe<ProjectUpdatedMessage>(OnProjectUpdated);
    }

    private void OnProjectUpdated(ProjectUpdatedMessage message)
    {
        // Buscar el proyecto en la colección y actualizarlo
        var project = Projects.FirstOrDefault(p => p.Id == message.ProjectId);
        if (project != null)
        {
            project.Name = message.ProjectName;
            // Actualizar otras propiedades según sea necesario

            // Notificar que el proyecto ha cambiado
            OnPropertyChanged(nameof(Projects));
        }
        else
        {
            // Opcional: agregar el proyecto si no existe
            Projects.Add(new Project
            {
                Id = message.ProjectId,
                Name = message.ProjectName
                // Asignar otras propiedades según sea necesario
            });
        }
    }

    // Implementación de INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string name = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
```

### Paso 5: Configurar la Vista Principal (MainPage)

En la `MainPage`, vinculamos el *ViewModel* para que refleje los cambios en la interfaz de usuario automáticamente.

```xml
<Page
    x:Class="MyApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp"
    xmlns:vm="using:MyApp.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.DataContext>
        <vm:MainViewModel x:Name="ViewModel"/>
    </Page.DataContext>

    <Grid>
        <ListView ItemsSource="{Binding Projects}"
                  IsItemClickEnabled="True"
                  SelectionMode="None">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:Project">
                    <StackPanel Margin="10">
                        <TextBlock Text="{x:Bind Name}" FontSize="18" FontWeight="Bold"/>
                        <!-- Otras propiedades del proyecto -->
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>
```

### Paso 6: Actualizar la Vista de Edición o Detalle

Asegúrate de que la vista de edición o detalle del proyecto invoque el método de actualización que publica el mensaje.

```xml
<!-- EditProjectPage.xaml -->
<Page
    x:Class="MyApp.EditProjectPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp"
    xmlns:vm="using:MyApp.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Page.DataContext>
        <vm:EditProjectViewModel x:Name="ViewModel"/>
    </Page.DataContext>

    <Grid Padding="20">
        <StackPanel>
            <TextBox Text="{Binding ProjectName, Mode=TwoWay}" PlaceholderText="Nombre del Proyecto"/>
            <!-- Otros campos de edición -->

            <Button Content="Guardar" Click="SaveButton_Click" Margin="0,20,0,0"/>
        </StackPanel>
    </Grid>
</Page>
```

```csharp
// EditProjectPage.xaml.cs
public sealed partial class EditProjectPage : Page
{
    public EditProjectViewModel ViewModel => DataContext as EditProjectViewModel;

    public EditProjectPage()
    {
        this.InitializeComponent();
    }

    private void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        ViewModel.UpdateProject();
        // Navegar de vuelta a la MainPage u otra lógica
    }
}
```

## Uso del Messenger en la MainPage

El *ViewModel* de la `MainPage` ya está suscrito a los mensajes de actualización de proyectos. Cada vez que se edita o se detalla un proyecto en otra parte de la aplicación, el mensaje correspondiente se publica y la `MainPage` actualiza su colección de proyectos en consecuencia.

### Flujo de Actualización

1. **Edición del Proyecto:**
   * El usuario edita un proyecto en la `EditProjectPage`.
   * Al guardar los cambios, el *ViewModel* de edición publica un `ProjectUpdatedMessage` con la información actualizada.
2. **Recepción del Mensaje:**
   * El *ViewModel* de la `MainPage` está suscrito a `ProjectUpdatedMessage`.
   * Al recibir el mensaje, busca el proyecto correspondiente en su colección y actualiza sus propiedades.
3. **Actualización de la Interfaz:**
   * Debido a la implementación de `INotifyPropertyChanged`, la interfaz de usuario se actualiza automáticamente para reflejar los cambios.

## Ventajas de Utilizar el Messenger

* **Desacoplamiento de Componentes:** Los *ViewModels* no necesitan referencias directas entre sí, lo que facilita la mantenibilidad.
* **Escalabilidad:** Facilita la comunicación entre múltiples *ViewModels* sin incrementar la complejidad.
* **Reusabilidad:** Los mensajes pueden ser utilizados por cualquier parte de la aplicación que lo necesite.

## Consideraciones Finales

Implementar un **Messenger** basado en el patrón *publicador/suscriptor* es una excelente manera de gestionar la comunicación entre diferentes partes de una aplicación UWP siguiendo el patrón **MVVM**. Asegura que los componentes permanezcan desacoplados y facilita la escalabilidad y mantenibilidad del código.

Al seguir esta implementación, podrás actualizar la `MainPage` desde las vistas de edición y detalle de proyectos de manera eficiente y limpia, mejorando la experiencia de desarrollo y la calidad de la aplicación.

**Referencia Adicional:** Para profundizar en la implementación del patrón Messenger y su uso en aplicaciones MVVM, puedes consultar el siguiente recurso:

* [Messenger en el MVVM Toolkit (Microsoft Learn)](https://learn.microsoft.com/es-es/dotnet/communitytoolkit/mvvm/messenger)
