Compartilhar via


Marcando Eventos Roteados como Manipulados e Manipulação de Classes

Manipuladores para um evento roteado podem marcar o evento manipulado dentro dos dados do evento. Manipular o evento vai efetivamente encurtar a rota. Manipula?ão de classes é um conceito de programação suportado por eventos roteados. Um manipulador de classes tem a oportunidade de manipular um evento roteado particular no nível de uma classe com um manipulador que é invocado antes de qualquer manipulador de instância em qualquer instância da classe.

Este tópico contém as seguintes seções.

  • Pré-requisitos
  • Quando Marcar Eventos como Manipulados
  • "Visualização" versus eventos (encapsulamento).S evento bubbling e tratamento de evento
  • Manipuladores de Classe e de Instância
  • Manipulação de Classe de Eventos Roteados por Classes Base de Controles
  • Acrescentando Manipuladores de Instância que são Disparados Quando Eventos São Marcados como Manipulados
  • Suprimindo Propositalmente Eventos de Entrada para Composição de Controle
  • Tópicos relacionados

Pré-requisitos

Este tópico elabora conceitos introduzidos no Visão geral sobre eventos roteados.

Quando Marcar Eventos como Manipulados

Quando você define o valor da propriedade Handled como true nos dados de um evento roteado, isso significa "marcar um evento como manipulado". Não há uma regra absoluta para quando você d3eve marcar eventos roteados como manipulados, seja como um autor de aplicação ou um autor de controle que responde a eventos roteados existentes ou implementa novos eventos roteados. Na maioria das vezes, o conceito de "manipulado" nos dados de um evento roteado deve ser utilizado como um protocolo limitado para as respostas da sua própria aplicação aos vários eventos roteados expostos em WPF APIs assim como em quaisquer eventos roteados personalizados. Outra maneira de considerar a questão "controlada" é que geralmente é preciso marcar um evento roteado manipulado se seu código respondido a eventos roteados de forma significativa e relativamente completa. Normalmente, não deve haver mais de uma resposta significativa que exige implementações manipulador separado para qualquer ocorrência de eventos roteados único. Se mais respostas forem necessárias, então o cógido necessário deve ser implementado através de lógica de aplicação que esteja encadeada dentro de um único manipulador em vez de utilizar o sistema de evento roteado para encaminhar. O conceito do que é "significativo" também é subjetivo, e depende da sua aplicação ou código. sistema autônomo orientação geral sobre alguns exemplos de "resposta significativa" incluem: Definindo o foco, modificando o estado público, a definição de propriedades que afetam a representação visual e disparar outros eventos novos. Exemplos de respostas nonsignificant incluem: Modificar estado particular (sem nenhum impacto visual, ou representação programática), o registro de eventos, ou observando os argumentos de um evento e optando por não responder a ele.

O comportamento do evento roteado reforça esse modelo de "resposta significativa" para utilizar o estado manipulado de um evento roteado, porque manipuladores acrescentados em XAML ou a assinatura comum de AddHandler não são invocados em resposta a um evento roteado onde os dados do evento já estão marcados como manipulados. Você deve ainda acrescentar um manipulador com a versão de parâmetro handledEventsToo (AddHandler(RoutedEvent, Delegate, Boolean)) para manipular eventos roteados marcados como manipulados por participantes anteriores na rota do evento.

Em algumas circunstâncias, os próprios controles marcam certos eventos roteados como manipulados. Um evento roteado manipulado representa uma decisão dos autores de controle WPF que as ações do controle em resposta do evento roteado são significativas ou completas como parte da implementação do controle, e que o evento não precisa mais de tratamento. Geralmente isso é feito acrescentando um manipulador de classe para um evento, ou sobrepondo um dos virtuais de manipulador de classe que existem na classe base. Você ainda pode contornar essa manipulação de eventos se necessário; veja Contornando a Supressão de Eventos por Controles mais adiante neste tópico.

"Visualização" versus eventos (encapsulamento).S evento bubbling e tratamento de evento

Eventos roteados de exibição são eventos que seguem uma rota túnel através da árvore de elementos. A "Visualização" expressa na convenção de nomes indica o princípio geral para os eventos de entrada que eventos roteados tunneling (de exibição) são disparados antes do evento roteaod bubbling. Além disso, eventos roteados de entrada que têm um par tunneling e bubbling têm uma lógica de manipulação distinta. Se o evento roteado tunneling é marcado como manipulado por um evento ouvinte, então o evento roteado bubbling será marcado como manipulado mesmo antes de quaisquer ouvintes do evento roteado bubbling o receberem-no. Os eventos roteados tunneling e bubbling são tecnicamente eventos separados, mas eles deliberadamente compartilham a mesma instâcia de dados de evento para permitir esse comportamento.

A conexão entre os eventos roteados tunneling e bubbling é atingida através da implementação interna de como uma classe WPF dispara seus próprios eventos roteados declarados, e isso é verdade para os eventos roteados de entrada em pares. Mas, a menos que essa implementação de nível de classe existe, não há nenhuma conexão entre um evento roteado encapsulamento e um evento roteado bubbling que compartilham o esquema de nomeação: sem essa implementação eles seriam dois eventos roteados totalmente separados e não devem ser aumentados em sequência ou compartilhamento de dados de eventos.

Para mais informações sobre como implementar pares de eventos roteados de entrada tunnel/bubble em uma classe personalizada, veja Como: Criar um evento roteado personalizado.

Manipuladores de Classe e de Instância

Eventos roteados considere dois tipos diferentes de ouvintes de evento: ouvintes de classe e instância ouvintes. Ouvintes de classe existem porque tipos chamaram um EventManager API particular, RegisterClassHandler no seu construtor estático, ou sobrepuseram um método virtual de manipulador de classe de uma classe base de elementos. Instância ouvintes são instâncias de determinada classe/elementos onde um ou mais manipuladores foram anexadas para esse evento roteado por uma telefonar para AddHandler. Existente WPF roteado eventos fazer chamadas para AddHandler sistema autônomo parte do common language runtime (CLR) evento wrapper {} de adicionar e remover {} implementações do evento, que também é sistema autônomo simples XAML mecanismo de anexar manipuladores de eventos por meio de uma sintaxe de atributo está habilitado. Assim, mesmo a utilização simples XAML equivale a uma chamada AddHandler.

Elementos na árvore visual são verificados para implementações de manipuladores registrados. Manipuladores são invocados potencialmente em toda a rota, na ordem inerente ao tipo de estratégia de roteamento para aquele evento roteado. Por exemplo, eventos roteados bubbling vão primeiro invocar os manipuladores que estiverem anexados ao mesmo elemento que disparou o evento roteado. Então o evento roteado vai para o próximo elemento pai e assim sucessivamente até que o elemento raiz da aplicação seja alcançado.

Da perspectiva de um elemento raiz na rota, se a manipulação de classe ou qualquer elemento mais próximo da origem do evento roteado invoca manipuladores que marcam os argumentos do evento como tendo sido manipulados, então manipuladores nos elementos raiz não são invocados, e a rota de eventos é encurtada efetivamente antes de alcançar aquele elemento raiz. Entretanto, a rota não é completamente interrompida, porque manipuladores podem ser acrescentados utilizando um condicional especial de que eles devem ainda ser invocados, mesmo que um manipulador de classe ou instância tenha marcado o evento roteado como manipulado. Isso é explicado em Acrescentando Manipuladores de Instância que são Disparados Mesmo Quando Eventos são Marcados como Manipulados, mais adiante nesse tópico.

Num nível mais profundo que a rota de eventos, também há potencialmente múltiplos manipuladores de classe para uma determinada instância de uma classe. Isso ocorre porque o modelo de manipulação de classe para eventos roteados permite que cada uma das classes numa hierarquia de classes registre seu próprio manipulador de classe para cada evento roteado. Cada manipulador de classe é acrescentado a um armazenamento interno, e a rota de eventos de uma aplicação é construída, os manipuladores de classes são todos acrescentados à rota de eventos. Manipuladores de classe são acrescentados à rota para que o manipulador de classe mais derivado seja invocado primeiro, e manipuladores de classe de cada classe base sucessiva sejam invocados em seguida. Em geral, manipuladores de classe não são registrados para que respondam a eventos roteados que já foram marcados como manipulados. Portanto, esse mecanismo de manipulação de classes permite duas alternativas:

  • Classes derivadas podem suplementar a manipulação de classe herdada da classe base acrescentando um manipulador que não marque o evento roteado como manipulado, porque o manipulador da classe base será invocado algum tempo depois do manipulador de classe derivada.

  • Classes derivadas podem substituir a manipulação de classes da classe base acrescentando um manipulador de classe que marca o evento roteado como manipulado. Você deve tomar cuidado com essa abordagem, porque muda potencialmente o design de controle de base pretendido em áreas como aparência visual, lógica de estados, manipulação de entrada e de comandos.

Manipulação de Classe de Eventos Roteados por Classes Base de Controles

Para cada nó de elemento em uma rota de eventos, ouvintes de classe têm a oportunidade de responder ao evento roteado antes que qualquer ouvinte de instância do elemento possa fazê-lo. Por isso, manipuladores de classe são às vezes utilizados para suprimir eventos roteados que uma implementação de classe de controle particular não quer propagar mais adiante, ou para oferecer manipulação especial daquele evento roteado que seja uma característica da classe. Por exemplo, uma classe pode disparar seu próprio evento específico de classe que contém mais especificidades sobre o que alguma condição de entrada do usuário significa no contexto daquela classe específica. A implementação de classe pode então marcar o evento roteado mais geral como manipulado. Manipuladores de classe geralmente são acrescentados para que não sejam invocados para eventos roteados quando dados de evento compartilhados já tenham sido marcados como manipulados, mas para casos atípicos também tem uma assinatura RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) que registra manipuladores de classe para invocá-los mesmo quando eventos roteados são marcados como manipulados.

Virtuais de Manipulador de Classe

Alguns elementos, em particular os elementos base como UIElement, expõem métodos virtuais vazios "On*Event" e "OnPreview*Event" que correspondem à sua lista de eventos roteados públicos. Esses métodos virtuais podem ser sobrepostos para implementar um manipulador de classe para aquele evento roteado. As classes de elemento base registram esses métodos virtuais como seu manipulador de classe para cada evento roteado utilizando RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) como descrito anteriormente. Os métodos virtuais On*Event tornam mais fácil implementar manipulação de classe para os eventos roteados relevantes, sem requerer inicialização especial em construtores estáticos para cada tipo. Por exemplo, você pode acrescentar manipulação de classe para o evento DragEnter em qualquer classe derivadaUIElement sobrepondo o método virtual OnDragEnter. Dentro da sobreposição, você pode manipular o evento roteado, disparar outros eventos, iniciar lógica específica da classe que pode mudar propriedades de elementos em instâncias, ou uma combinação dessas ações. Você deve geralmente chamar a implementação base em tais sobreposições mesmo quando você marca o evento como manipulado. Chamar a implementação base é fortemente recomendado porque o método virtual está na classe base. O padrão virtual protegido de chamar as implementações base de cada virtual essencialmente substitui e se assemelha a um mecanismo semelhante nativo à manipulação de classes de eventos roteados, pelo qual manipuladores de classe de todas as classes numa hierarquia de classes são chamados em uma data instância, começando com o manipulador de classe mais derivada e continuando até o manipulador da classe base. Você deve omitir a chamada à implementação base apenas se sua classe tem um requisito proposital de mudar a lógica de manipulação da classe base. Se você chama a classe base antes ou depois de sobrepor o código vai depender da natureza da sua implementação.

Manipulação de Classe de Evento de Entrada

Os métodos virtuais de manipulação de classe são todos registrados para que só sejam invocados caso dados de evento compartilhados não estejam ainda marcados como manipulados. Além disso, para os eventos de entrada unicamente, as versões tunneling e bubbling tipicamente são disparadas em sequência e compartilham dados de evento. Isso implica que para um dado par de manipuladores de classe para eventos de entrada onde um é versão tunneling e outro versão bubbling, você pode não querer marcar o evento como manipulado imediatamente. Se você implementa o método virtual de manipulação de classe tunneling para marcar o evento como manipulado, isso evitará que o manipulador de classe bubbling seja invocado (assim como evitará que os manipuladores de instância registrados normalmente para o evento tunneling ou bubbling sejam invocados).

Uma vez que a manipulação de um nó esteja completa, os ouvintes de instância são considerados.

Acrescentando Manipuladores de Instância que são Disparados Quando Eventos São Marcados como Manipulados

O método AddHandler oferece uma sobrecarga particular que permite que você acrescente manipuladores que serão invocados pelo sistema de eventos sempre que um evento alcançar o elemento manipulador na rota, mesmo que outro manipulador já tenha ajustado os dados de evento para marcar o evento como manipulado. Isso geralmente não é feito. Geralmente, manipuladores podem ser escritos para ajustar todas as áreas do código da aplica geralmenteão que possa ser influenciado por um evento, não importando onde ele foi manipulado numa árvore de elementos, mesmo se resultados múltiplos forem desejados. Além disso, geralmente só há um elemento que precisa responder ao evento, e a lógica de aplicação adequada já ocorreu. Mas a sobrecarga handledEventsToo está disponível para os casos excepcionais em que algum outro elemento da árvore de elementos ou composição de controle já marcou um evento como manipulado, mas outros eventos que estejam acima ou abaixo na árvore de elementos (dependendo da rota) ainda querem ter seus próprios manipuladores invocados.

Quando Marcar Eventos Manipulados como Não Manipulados

Em geral, eventos roteados que são marcados como manipulados não devem ser marcados como não manipulados (Handled definido de volta como false) mesmo por manipuladores que atuem em handledEventsToo. Entretanto, alguns eventos de entrada têm representações de evento de alto e baixo nível que podem se sobrepor quando o evento de alto nível é visto numa posição da árvore e o evento de baixo nível em outra posição. Por exemplo, considere o caso em que um elemento filho ouve um elemento de alto nível como um TextInput enquanto um elemento pai ouve um evento de baixo nível como um KeyDown. Se o elemento pai manipula o evento de baixo nível, o evento de alto nível pode ser suprimido mesmo no elemento filho que intuitivamente deveria ter a primeira oportunidade de manipular o evento.

Nessas situações, pode ser necessário acrescentar manipuladores para os elementos pai e filho para o evento de baixo nível. A implementação de manipulador de elemento filho pode marcar o elemento de baixo nível como manipulado, mas a implementação de manipulador de evento pai defini-lo-ia como não manipulado novamente para que elementos adiante na árvore (assim como o evento de alto nível) possam ter a oportunidade de responder. Essa situação deveria ser bastante rara.

Suprimindo Propositalmente Eventos de Entrada para Composição de Controle

O principal cenário onde a manipulação de classe de eventos roteados é utilizada é para eventos de entrada e controles compostos. Um controle composto é por definição composto de múltiplos controles práticos ou classes base de controles. Com frequência o autor do controle deseja juntar todos os eventos de entrada possíveis que cada um dos subcomponentes pode disparar, para relatar para o controle inteiro como uma única fonte de eventos. Em alguns casos o autor do controle pode desejar suprimir os eventos de componentes inteiramente, ou substituir um evento definido por componente que carrega mais informação ou implica um comportamento mais específico. The canonical example that is immediately visible to any component author is how a Windows Presentation Foundation (WPF) Button handles any mouse event that will eventually resolve to the intuitive event that all buttons have: a Click evento.

A classe base Button (ButtonBase) deriva de Control que por sua vez deriva de FrameworkElement e UIElement e muito da infraestrutura de evento necessária para o processamento da entrada está disponível no nível UIElement. Em particular, UIElement processos Geral Mouse eventos que lidar com testes de visitas para o cursor do mouse no seus limites e fornece eventos distintos para sistema autônomo ações de botão mais comuns, sistema autônomo MouseLeftButtonDown. UIElement também fornece um vazio virtual OnMouseLeftButtonDown sistema autônomo o manipulador de classe pré-registrados de MouseLeftButtonDown, e ButtonBase substitui-lo. De forma semelhante, ButtonBase utiliza manipuladores de classe para MouseLeftButtonUp. Na sobreposição, em que são passados os dados de evento, as implementações marcam a instância RoutedEventArgs como manipulada, definindo Handled como true, e aqueles mesmos dados de evento continuam ao longo da rota restante para outros manipuladores de classe e também para manipuladores de instância ou configuradores de evento. Além disso, a sobreposição OnMouseLeftButtonUp dispara em seguida Click. O resultado participante para a maioria dos ouvintes que será o MouseLeftButtonDown e MouseLeftButtonUpeventos "desaparecerem" e são substituídos em vez por Click, um evento que contém mais indicando como se sabe que esse evento originado de um botão true e não alguma parte composto do botão ou de algum Outros elemento totalmente.

Contornando Supressão de Eventos por Controles

Às vezes esse comportamento de supressão de eventos em controles individuais pode interferir com uma intenção mais geral de lógica de manipulação de eventos da sua aplicação. Por exemplo, se por algum motivo sua aplicação tinha um manipulador para MouseLeftButtonDown localizado no elemento raiz da aplicação, você perceberá que qualquer clique do mouse em um botão não invocaria manipuladores MouseLeftButtonDown ou MouseLeftButtonUp no nível raiz. O próprio evento realmente emergiu (de novo, rotas de evento não são realmente terminadas, mas o sistema de eventos roteados muda seu comportamento de invocação de manipulador após ser marcado como manipulado. Quando e evento roteado alcança o botão, a manipulação da classe ButtonBase marcou o MouseLeftButtonDown como manipulado porque queria substituir o evento Click com mais significado. Portanto, qualquer manipulador padrão MouseLeftButtonDown adiante na rota não seria invocado. Há duas técnicas que você pode utilizar para assegurar que seus manipuladores serão invocados nessa circunstância.

A primeira técnica é adicionar o manipulador usando o deliberadamentehandledEventsToo assinatura do AddHandler(RoutedEvent, Delegate, Boolean). Uma limitação desta abordagem é que esse técnica de anexar um manipulador de eventos só é possível por código, e não por marcação. A sintaxe simples de especificar o nome do manipulador de eventos como um valor de atributo de evento via Extensible Application Markup Language (XAML) não permite esse comportamento.

A segunda técnica funciona apenas com eventos de entrada, onde as versões tunneling e bubbling do evento roteado são pareadas. Para esses eventos roteados, você pode acrescentar manipuladores ao evento roteado equivalente de visualização/tunneling. Aquele evento roteado vai começar da raiz, de forma que o código manipulador da classe botão não vai interceptá-lo, presumindo que você já anexou o manipulador de Preview a algum nível de elemento ancestral na árvore de elementos da aplicação. Se você usa essa abordagem, tome cuidado ao marcar qualquer evento Preview como manipulado. Para o exemplo dado com PreviewMouseLeftButtonDown sendo manipulado no elemento raiz, se você marcou o evento como Handled na implementação do manipulador, você de fato suprimiria o evento Click. Isso geralmente não é comportamento desejado.

Consulte também

Tarefas

Como: Criar um evento roteado personalizado

Conceitos

Visualização de Eventos

Visão geral sobre eventos roteados

Referência

EventManager