Compartilhar via


Padrões WeakEvent

Em aplicativos típicos, é possível que manipuladores que estão conectados a origens de eventos não serão destruídos em coordenação com o objeto de escuta que anexaram o manipulador à fonte. Essa situação pode levar a vazamentos de memória. Windows Presentation Foundation (WPF) apresenta um padrão de design específico que pode ser usado para resolver esse problema, fornecendo uma classe de gerente dedicado para eventos específicos e implementar uma interface em ouvintes para esse evento. Esse padrão de design é conhecido como Padrão WeakEvent.

Por que implementar o Padrão WeakEvent?

Escutar eventos pode resultar em vazamentos de memória. A técnica comum para ouvir um evento é para usar a sintaxe específica do idioma que conecta um manipulador a um evento em uma fonte. Por exemplo, em C#, essa sintaxe é: source.SomeEvent += new SomeEventHandler(MyEventHandler).

Essa técnica cria uma referência de alta segurança da fonte de evento para o ouvinte de eventos. Normalmente, anexar um manipulador de eventos em um ouvinte faz com que o ouvinte tenha uma vida útil de objeto influenciado pela vida útil de objeto para a fonte (a menos que o manipulador de eventos é explicitamente removido). Mas em determinadas circunstâncias você pode desejar que o tempo de vida do objeto para o ouvinte seja controlado somente por outros fatores, como se ele pertencesse à árvore visual do aplicativo e não pelo tempo de vida de origem. Sempre que o tempo de vida do objeto de fonte estão ultrapassando o tempo de vida do objeto de ouvinte, o padrão de evento normal leva a um perda de memória: o ouvinte mais do que o objetivo é mantido ativo.

O padrão WeakEvent foi projetado para resolver esse problema de vazamento de memória. O WeakEvent padrão pode ser usado sempre que um ouvinte precisa registrar um evento, mas o ouvinte explicitamente não sabe quando cancelar o registro, e sempre que o tempo de vida de objeto de origem excede o Tempo de vida "útil" do objeto do ouvinte. (O conceito de "útil" é você quem define.) O padrão WeakEvent permite que o ouvinte registre e receba o evento sem afetar as características de vida útil de objeto do ouvinte de alguma forma. Na verdade, a referência implícita da fonte não conta ao decidir se o ouvinte está qualificado para coleta de lixo. A referência é uma referência fraca, daí a nomeação de padrão WeakEvent e os APIs relacionados. O ouvinte pode ser coletado como lixo ou destruído caso contrário, e a fonte pode continuar sem reter manipulador referências não colecionáveis para um objeto agora destruído.

Quem deve implementar o padrão WeakEvent?

Implementar o padrão WeakEvent será interessante principalmente para autores de controle. Isso ocorre porque como um autor de controle, você é basicamente responsável pelo comportamento e confinamento de seu controle e o seu impacto em aplicativos em que ele é inserido. Isso inclui o comportamento da vida útil de objeto de controle, em particular o tratamento do problema de vazamento de memória descrito.

Certas situações inerentemente levam aplicativos ao padrão WeakEvent. Um esse cenário é associação de dados, onde é geralmente um objeto de origem que é um fonte de dados é completamente independente de um objeto de escuta, que é um destino de uma ligação. Muitos aspectos da associação de dados WPF já tem o padrão WeakEvent aplicado em como os eventos são implementados.

Como implementar o padrão WeakEvent

Implementar o padrão WeakEvent consiste três aspectos:

  • Derive um gerente da classe WeakEventManager.

  • Implementar a interface IWeakEventListener em qualquer classe que deseja registrar ouvintes para o evento fraco sem gerar uma referência forte para a fonte.

  • Ao registrar ouvintes, não use os assessores add e remove convencionais do evento onde você deseja que o ouvinte use o padrão. Em vez disso, use as implementações "AddListener" e "RemoveListener" no WeakEventManager dedicado para o evento.

WeakEventManager

Normalmente, você criará classes gerente em uma relação 1: 1 para eventos que implementam o padrão. Por exemplo, se você tiver um evento Spin, você deve derivar uma classe SpinEventManager como o gerente dedicado de evento fraco para o evento. Se o evento existiu em mais de uma classe de origem, e se comportou o mesmo em cada classe e compartilhado a tipo de dados de eventos, o mesmo gerente poderá ser usado para cada.

A lista de verificação de implementação para derivar da classe WeakEventManager consiste de substituir dois métodos virtuais e expor vários outros membros cujos nomes não são especificamente regidos pelo modelo virtual, mas devem existir mesmo assim. As substituições são usadas para iniciar ou finalizar o modo de entrega de eventos por infraestrutura WPF. Os outros membros são necessários para fornecer funcionalidade para que suas próprias implementações IWeakEventListener possam usar o WeakEventManager para anexar o evento ouvintes.

Para anotações detalhadas de implementação para derivar de WeakEventManager, consulte "Observações para Herdeiros" no tópico WeakEventManager de referência.

IWeakEventListener

An IWeakEventListener a classe de implementação tem apenas uma responsabilidade: Implementando a interface do método ReceiveWeakEvent. A implementação ReceiveWeakEvent deve ser uma implementação centralizada que direciona qualquer referência de eventos que existe em classe para o WeakEventManager apropriado.

Para anotações detalhadas de implementação para implementar a interface IWeakEventListener, consulte "Observações para Implementers" no tópico ReceiveWeakEvent Método de referência.

Anexando Listeners (Ouvintes)

Suponha que você tivesse um evento ClockwiseSpin (definido por Spinner) que é um evento convencional. Para usar o padrão para este evento, você usaria uma classe ClockwiseSpinEventManager existente derivada de WeakEventManager, ou implementá-lo você mesmo. Se você tiver uma classe SpinListener de escuta que quer ser um ouvinte, a técnica convencional (não usando o padrão) para anexar o manipulador seria para usar a sintaxe +=:

spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);

Mas se você tem uma classe que implementa IWeakEventListener e conta para o evento ClockwiseSpin e seu gerente na implementação, a sintaxe para usar o padrão WeakEvent em vez disso, é:

ClockwiseSpinEventManager.AddListener(spinnerInstance, this);

Em seguida, sua lógica de tratamento para esse evento é especificada dentro de uma das ocorrências da implementação em sua classe, ReceiveWeakEvent não como um manipulador convencional com base em delegado.

Implementando o padrão para eventos externos

Um aspecto interessante do padrão WeakEvent é que você pode implementar o padrão contra um evento que não é parte do seu código base. Da perspectiva da fonte, a maneira que os manipuladores são anexados ao seu evento não difere e é controlada pelo WeakEventManager. Você só precisará definir um WeakEventManager para esse evento e, em seguida, contar para o evento como parte da lógica de ReceiveWeakEvent em qualquer escuta em potencial que deseja usar o padrão para ouvir desse evento.

Consulte também

Conceitos

Visão geral sobre eventos roteados

Revisão de Associação de Dados

Referência

WeakEventManager

IWeakEventListener