FrameworkElement.EffectiveViewportChanged Evento

Definição

Ocorre quando o visor efetivo do FrameworkElement é alterado.

// Register
event_token EffectiveViewportChanged(TypedEventHandler<FrameworkElement, EffectiveViewportChangedEventArgs const&> const& handler) const;

// Revoke with event_token
void EffectiveViewportChanged(event_token const* cookie) const;

// Revoke with event_revoker
FrameworkElement::EffectiveViewportChanged_revoker EffectiveViewportChanged(auto_revoke_t, TypedEventHandler<FrameworkElement, EffectiveViewportChangedEventArgs const&> const& handler) const;
public event TypedEventHandler<FrameworkElement,EffectiveViewportChangedEventArgs> EffectiveViewportChanged;
function onEffectiveViewportChanged(eventArgs) { /* Your code */ }
frameworkElement.addEventListener("effectiveviewportchanged", onEffectiveViewportChanged);
frameworkElement.removeEventListener("effectiveviewportchanged", onEffectiveViewportChanged);
- or -
frameworkElement.oneffectiveviewportchanged = onEffectiveViewportChanged;
Public Custom Event EffectiveViewportChanged As TypedEventHandler(Of FrameworkElement, EffectiveViewportChangedEventArgs) 

Tipo de evento

Requisitos do Windows

Família de dispositivos
Windows 10, version 1809 (introduzida na 10.0.17763.0)
API contract
Windows.Foundation.UniversalApiContract (introduzida na v7.0)

Comentários

Um controle de rolagem permite que o usuário percorra/role o conteúdo que ocupa mais espaço do que o disponível na interface do usuário. A parte do conteúdo que o usuário vê é chamada de visor.

O evento EffectiveViewportChanged fornece várias informações:

  1. O EffectiveViewport real
  2. Um cálculo para o MaxViewport
  3. Valores escalares para BringIntoViewDistanceX e BringIntoViewDistanceY

EffectiveViewport

O EffectiveViewport é a interseção de todos os visores conhecidos que contêm o FrameworkElement em sua subárvore. Se houver dois ou mais visores (por exemplo, um ScrollViewer aninhado dentro de outro ScrollViewer) que não se sobrepõem, o EffectiveViewport será um Rect vazio.

Observação

Para que o visor de um controle de rolagem seja conhecido pela estrutura, o controle deve tê-lo registrado anteriormente usando o método UIElement.RegisterAsScrollPort . A estrutura usa o Clip do elemento registrado ao determinar o visor efetivo.

Quando o visor do controle de rolagem é alterado, ele deve invocar seu método InvalidateViewport para informar à estrutura que seu visor foi alterado e qualquer um de seus subconjuntos que escutam o visor efetivo precisa ser notificado sobre as alterações.

O EffectiveViewport é fornecido no espaço de coordenadas do FrameworkElement. Não é necessário executar um TransformToVisual com o visor Rect.

Em um cenário simples em que há um ScrollViewer que contém um único elemento, o evento EffectiveViewportChanged fornece atualizações de visor semelhantes ao evento ViewChanged . A main diferença é que o evento EffectiveViewportChanged é gerado após o passe de organização do layout.

Por exemplo, este ...

<ScrollViewer>
    <Grid Height="4000" Width="4000"
          EffectiveViewportChanged="Grid_EffectiveViewportChanged"/>
</ScrollViewer>

... fornece informações semelhantes do visor como esta...

<ScrollViewer ViewChanged="ScrollViewer_ViewChanged">
    <Grid Height="4000" Width="4000"/>
</ScrollViewer>

MaxViewport

O MaxViewport é semelhante ao EffectiveViewport, mas em vez de representar uma interseção simples dos visores conhecidos, ele representa a interseção dos visores como se cada um tivesse sido colocado em exibição de qualquer visor externo. A Rect resultante representa duas coisas:

  1. o maior tamanho que o EffectiveViewport pode ser (considerando os tamanhos atuais do visor) e
  2. a posição do visor efetivo máximo em relação ao FrameworkElement.

Essas informações podem ser usadas para medir onde e quanto conteúdo o FrameworkElement deve gerar previamente para potencialmente preencher o visor antes de ser rolado para exibição.

Observação

A rolagem por meio de entrada direta, como toque ou caneta, é manipulada pelo sistema em um processo separado. Por padrão, a rolagem é tratada de forma assíncrona para o thread da interface do usuário. Os controles que executam a virtualização podem precisar pré-gerar conteúdo bem antes de entrar no visor devido ao custo inerente da criação do elemento.

Atrasar toda a preparação de conteúdo até entrar em exibição pode levar a uma experiência de rolagem ruim para os usuários. Os usuários podem ver espaço em branco ou gaguejar, ambos os sintomas do thread da interface do usuário não podem acompanhar a velocidade do movimento panorâmico.

A posição do MaxViewport é relatada no espaço de coordenadas do FrameworkElement. Se o MaxViewport fosse transformado no espaço de coordenadas do primeiro visor na cadeia de ancestrais do FrameworkElement, o Rect estaria dentro dos limites desse primeiro visor.

BringIntoViewDistanceX e Y

Esses valores indicam o quão perto o FrameworkElement deve se tornar visível maximicamente em todos os seus visores.

Se o valor for maior que zero, mas menor que ActualWidth / ActualHeight , o elemento estará parcialmente dentro do visor visível pelo usuário. Quando os valores forem zero, o FrameworkElement estará totalmente dentro do visor visível pelo usuário.

Dica

Isso não garante que o elemento esteja visível para o usuário, pois outros elementos com uma ordem Z mais alta ainda podem estar ocluindo o FrameworkElement.

Declarados mais formalmente, esses valores são a soma da distância absoluta que o FrameworkElement seria convertido ao atender a uma chamada para StartBringIntoView. Os valores não explicam a possibilidade de um controle de rolagem ter a rolagem desabilitada.

<ListView x:Name="lv">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="x:String">
            <UserControl Tag="{x:Bind}"
                         EffectiveViewportChanged="Item_EffectiveViewportChanged"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
private void Item_EffectiveViewportChanged(FrameworkElement sender, EffectiveViewportChangedEventArgs args)
{
    // If we wanted to know if a list item (w/ vertical scrolling only) is partially within the viewport
    // then we can just check the BringIntoViewDistanceY of the event args.  If the distance is 0 then the item is fully within
    // the effective viewport.  If the BringIntoViewDistanceY is less than the sender's ActualHeight, then its
    // partially within the effective viewport.
    // The EffectiveViewport rect is relative to the sender, so we can use it to know where the element is within the viewport.  
    // NOTE: "Within the viewport" != visible to the user's eye, since another element may overlap and obscure it.
    if (args.BringIntoViewDistanceY < sender.ActualHeight)
    {
        Debug.WriteLine($"Item: {sender.Tag} has {sender.ActualHeight - args.BringIntoViewDistanceY} pixels within the viewport");
    }
    else
    {
        Debug.WriteLine($"Item: {sender.Tag} has {args.BringIntoViewDistanceY - sender.ActualHeight} pixels to go before it is even partially visible");
    }

    // Consider disconnecting from the effective viewport when not needed.  Otherwise, it is called on every viewport change.
    //lv.EffectiveViewportChanged -= Item_EffectiveViewportChanged;
}

Comportamento

  • Se o visor efetivo de um pai e um filho forem alterados, o pai receberá a notificação antes do filho.
  • O evento só é gerado para elementos na árvore de interface do usuário que participam do layout. Por exemplo, se o elemento não estiver na árvore dinâmica ou se a propriedade Visibility do elemento ou qualquer um de seus ancestrais estiver definida como Collapsed, esse evento não será gerado.
  • Embora o visor efetivo leve em conta transformações de renderização para todos os elementos ancestrais, ele não considera os efeitos do recorte (além do clipe do elemento registrado por um controle de rolagem como seu visor).
  • O visor efetivo não leva em conta a oclusão devido a outros elementos que têm uma ordem Z mais alta.

Aplica-se a

Confira também