Partilhar via


Comunicação entre componentes de acoplamento flexível

Gorjeta

Este conteúdo é um excerto do eBook, Enterprise Application Patterns Using .NET MAUI, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Padrões de aplicativos corporativos usando a miniatura da capa do eBook .NET MAUI .

O padrão publicar-assinar é um padrão de mensagens no qual os editores enviam mensagens sem conhecer nenhum destinatário, conhecido como assinante. Da mesma forma, os assinantes ouvem mensagens específicas, sem conhecer nenhum editor.

Os eventos no .NET implementam o padrão publish-subscribe e são a abordagem mais simples para uma camada de comunicação entre componentes se o acoplamento flexível não for necessário, como um controle e a página que o contém. No entanto, os tempos de vida do editor e do assinante são acoplados por referências de objeto entre si, e o tipo de assinante deve ter uma referência ao tipo de editor. Isso pode criar problemas de gerenciamento de memória, especialmente quando há objetos de curta duração que se inscrevem em um evento de um objeto estático ou de longa duração. Se o manipulador de eventos não for removido, o assinante será mantido vivo pela referência a ele no editor, e isso impedirá ou atrasará a coleta de lixo do assinante.

Introdução ao MVVM Toolkit Messenger

A interface do MVVM Toolkit IMessenger descreve o padrão publish-subscribe, permitindo a comunicação baseada em mensagem entre componentes que são inconvenientes para vincular por objeto e referências de tipo. Este mecanismo permite que editores e assinantes se comuniquem sem ter uma referência direta uns aos outros, ajudando a reduzir as dependências entre componentes, ao mesmo tempo em que permite que os componentes sejam desenvolvidos e testados de forma independente.

Nota

O MVVM Toolkit Messenger faz parte do CommunityToolkit.Mvvm pacote. Para obter informações sobre como adicionar o pacote ao seu projeto, consulte Introdução ao MVVM Toolkit no Microsoft Developer Center.

Aviso

O .NET MAUI contém uma classe interna MessagingCenter que não é mais recomendada para uso. Em vez disso, use o MVVM Toolkit Messenger.

A IMessenger interface permite a funcionalidade de publicação-assinatura multicast. Isso significa que pode haver vários editores que publicam uma única mensagem e pode haver vários assinantes ouvindo a mesma mensagem. A imagem abaixo ilustra essa relação:

Funcionalidade de publicação-subscrição de multicast.

Existem duas implementações da IMessenger interface que acompanham o CommunityToolkit.Mvvm pacote. O WeakReferenceMessenger usa referências fracas que podem resultar em limpeza mais fácil para os assinantes de mensagens. Esta é uma boa opção se os seus subscritores não tiverem um ciclo de vida claramente definido. O StrongReferenceMessenger usa referências fortes que podem resultar em um melhor desempenho e uma vida útil mais claramente controlada da assinatura. Se você tiver um fluxo de trabalho com um tempo de vida muito controlado (por exemplo, uma assinatura vinculada aos métodos e OnDisappearing páginas OnAppearing de uma página), a opção pode ser melhor, se o StrongReferenceManager desempenho for uma preocupação. Ambas as implementações estão disponíveis com implementações padrão prontas para uso fazendo referência a um WeakReferenceMessenger.Default ou StrongReferenceMessenger.Default.

Nota

Embora a interface permita a IMessenger comunicação entre classes de acoplamento flexível, ela não oferece a única solução arquitetônica para esse problema. Por exemplo, a comunicação entre um modelo de exibição e um modo de exibição também pode ser alcançada pelo mecanismo de vinculação e por meio de notificações de alteração de propriedade. Além disso, a comunicação entre dois modelos de visualização também pode ser alcançada através da passagem de dados durante a navegação.

O aplicativo multiplataforma eShop usa a WeakReferenceMessenger classe para se comunicar entre componentes de acoplamento flexível. O aplicativo define uma única mensagem chamada AddProductMessage. O AddProductMessage é publicado pela CatalogViewModel classe quando um item é adicionado ao carrinho de compras. Em troca, a CatalogView classe assina a mensagem e usa isso para destacar o produto adicionado com animação em resposta.

No aplicativo multiplataforma eShop, WeakReferenceMessenger é usado para atualizar a interface do usuário em resposta a uma ação que ocorre em outra classe. Portanto, as mensagens são publicadas a partir do thread em que a classe está executando, com os assinantes recebendo a mensagem no mesmo thread.

Gorjeta

Marshal para a interface do usuário ou thread principal ao executar atualizações da interface do usuário. Se as atualizações das interfaces do usuário não forem feitas nesse thread, isso pode fazer com que o aplicativo falhe ou se torne instável.

Se uma mensagem enviada de um thread em segundo plano for necessária para atualizar a interface do usuário, processe a mensagem no thread da interface do usuário no assinante invocando o MainThread.BeginInvokeOnMainThread método.

Para obter mais informações sobre Messengero , consulte Messenger no Microsoft Developer Center.

Definir uma mensagem

IMessenger As mensagens são objetos personalizados que fornecem cargas úteis personalizadas. O exemplo de código a seguir mostra a AddProductMessage mensagem definida no aplicativo multiplataforma eShop:

public class AddProductMessage : ValueChangedMessage<int>
{
    public AddProductMessage(int count) : base(count)
    {
    }
}

A classe base é definida usando ValueChangedMessage<T> onde T pode ser de qualquer tipo necessário para passar dados. Tanto os editores de mensagens como os subscritores podem esperar mensagens de um tipo específico (por exemplo, AddProductMessage). Isso pode ajudar a garantir que ambas as partes concordaram com um contrato de mensagens e que os dados fornecidos com esse contrato serão consistentes. Além disso, essa abordagem fornece segurança de tipo em tempo de compilação e suporte à refatoração.

Publicar uma mensagem

Para publicar uma mensagem, precisaremos usar o IMessenger.Send método. Isso pode ser acessado mais comumente através de WeakReferenceMessenger.Default.Send ou StrongReferenceMessenger.Default.Send. A mensagem enviada pode ser de qualquer tipo de objeto. O exemplo de código a seguir demonstra a publicação da AddProduct mensagem:

WeakReferenceMessenger.Default.Send(new Messages.AddProductMessage(BadgeCount));

Neste exemplo, o Send método especifica fornece uma nova instância do objeto para os AddProductMessage assinantes downstream receberem. Um segundo parâmetro de token adicional pode ser adicionado para usar quando vários assinantes diferentes precisam receber mensagens do mesmo tipo sem receber a mensagem errada.

O Send método publicará a mensagem e seus dados de carga útil, usando uma abordagem de fogo e esquecimento. Portanto, a mensagem é enviada mesmo que não haja assinantes registrados para receber a mensagem. Nessa situação, a mensagem enviada é ignorada.

Subscrever uma mensagem

Os subscritores podem registar-se para receber uma mensagem utilizando uma das IMessenger.Register<T> sobrecargas. O exemplo de código a seguir demonstra como o aplicativo multiplataforma eShop assina e processa a AddProductMessage mensagem:

WeakReferenceMessenger.Default
    .Register<CatalogView, Messages.AddProductMessage>(
        this,
        async (recipient, message) =>
        {
            await recipient.Dispatcher.DispatchAsync(
                async () =>
                {
                    await recipient.badge.ScaleTo(1.2);
                    await recipient.badge.ScaleTo(1.0);
                });
        });

No exemplo anterior, o Register método se inscreve na AddProductMessage mensagem e executa um delegado de retorno de chamada em resposta ao recebimento da mensagem. Esse delegado de retorno de chamada, especificado como uma expressão lambda, executa o código que atualiza a interface do usuário.

Nota

Evite o uso de dentro do seu delegado de retorno de this chamada para evitar a captura desse objeto dentro do delegado. Isso pode ajudar a melhorar o desempenho. Em alternativa, utilize o parâmetro recipient.

Se os dados de carga útil forem fornecidos, não tente modificar os dados de carga de dentro de um delegado de retorno de chamada porque vários threads podem estar acessando os dados recebidos simultaneamente. Nesse cenário, os dados de carga útil devem ser imutáveis para evitar erros de simultaneidade.

Cancelar a subscrição de uma mensagem

Os subscritores podem cancelar a subscrição de mensagens que já não querem receber. Isso é conseguido com uma das sobrecargas, como demonstrado no exemplo de IMessenger.Unregister código a seguir:

WeakReferenceMessenger.Default.Unregister<Messages.AddProductMessage>(this);

Nota

Neste exemplo, não é totalmente necessário chamar Unregister , pois permitirá que objetos WeakReferenceMessenger não utilizados sejam coletados como lixo. Se o StrongReferenceMessenger foram usados, seria aconselhável chamar Unregister para quaisquer assinaturas que não estão mais em uso.

Neste exemplo, a sintaxe do Unsubscribe método especifica o argumento type da mensagem e o objeto recipient que está escutando mensagens.

Resumo

A interface do MVVM Toolkit IMessenger descreve o padrão publish-subscribe, permitindo a comunicação baseada em mensagem entre componentes que são inconvenientes para vincular por objeto e referências de tipo. Este mecanismo permite que editores e assinantes se comuniquem sem ter uma referência uns aos outros, ajudando a reduzir as dependências entre componentes, ao mesmo tempo em que permite que os componentes sejam desenvolvidos e testados de forma independente.