FrameworkElement.EffectiveViewportChanged 이벤트

정의

FrameworkElement유효 뷰포트가 변경될 때 발생합니다.

// 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) 

이벤트 유형

Windows 요구 사항

디바이스 패밀리
Windows 10, version 1809 (10.0.17763.0에서 도입되었습니다.)
API contract
Windows.Foundation.UniversalApiContract (v7.0에서 도입되었습니다.)

설명

스크롤 컨트롤을 사용하면 사용자가 UI에서 사용할 수 있는 것보다 더 많은 공간을 차지하는 콘텐츠를 이동/스크롤할 수 있습니다. 사용자가 보는 콘텐츠의 부분을 뷰포트라고 합니다.

EffectiveViewportChanged 이벤트는 다음과 같은 여러 정보를 제공합니다.

  1. 실제 EffectiveViewport
  2. MaxViewport에 대한 계산
  3. BringIntoViewDistanceXBringIntoViewDistanceY에 대한 스칼라 값

EffectiveViewport

EffectiveViewport는 하위 트리에 FrameworkElement를 포함하는 알려진 모든 뷰포트의 교차점입니다. 겹치지 않는 두 개 이상의 뷰포트(예: 다른 ScrollViewer 내에 중첩된 ScrollViewer)가 있는 경우 EffectiveViewport는 빈 Rect입니다.

참고

스크롤 컨트롤의 뷰포트를 프레임워크에 알려 려면 이전에 UIElement.RegisterAsScrollPort 메서드를 사용하여 컨트롤을 등록해야 합니다. 프레임워크는 유효 뷰포트를 결정할 때 등록된 요소의 Clip 을 사용합니다.

스크롤 컨트롤의 뷰포트가 변경되면 InvalidateViewport 메서드를 호출하여 해당 뷰포트가 변경되었음을 프레임워크에 알리고 유효한 뷰포트를 수신하는 하위 요소에 변경 내용을 알려야 합니다.

EffectiveViewportFrameworkElement의 좌표 공간에 제공됩니다. 뷰포트 Rect를 사용하여 TransformToVisual을 수행할 필요가 없습니다.

단일 요소를 포함하는 ScrollViewer 가 있는 간단한 시나리오에서 EffectiveViewportChanged 이벤트는 ViewChanged 이벤트와 유사한 뷰포트 업데이트를 제공합니다. 기본 차이점은 레이아웃의 정렬 단계 후에 EffectiveViewportChanged 이벤트가 발생한다는 것입니다.

예를 들어 이 ...

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

... 는 이와 유사한 뷰포트 정보를 제공합니다.

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

MaxViewport

MaxViewportEffectiveViewport와 비슷하지만 알려진 뷰포트의 단순한 교집합을 나타내는 대신, 각 뷰포트가 외부 뷰포트의 보기로 가져온 것처럼 뷰포트의 교집합을 나타냅니다. 결과 Rect 는 다음 두 가지를 나타냅니다.

  1. EffectiveViewport가 될 수 있는 가장 큰 크기(현재 뷰포트 크기 제공) 및
  2. FrameworkElement를 기준으로 최대 유효 뷰포트의 위치입니다.

이 정보는 보기로 스크롤되기 전에FrameworkElement가 뷰포트를 채우기 위해 미리 생성해야 하는 콘텐츠의 위치와 양을 측정하는 데 사용할 수 있습니다.

참고

터치 또는 펜과 같은 직접 입력을 통해 스크롤하면 시스템에서 별도의 프로세스로 처리됩니다. 기본적으로 스크롤은 UI 스레드에 비동기적으로 처리됩니다. 가상화를 수행하는 컨트롤은 요소 만들기의 고유한 비용으로 인해 뷰포트에 들어가기 전에 콘텐츠를 미리 생성해야 할 수 있습니다.

보기에 올 때까지 모든 콘텐츠 준비를 지연하면 사용자에게 스크롤 환경이 저하될 수 있습니다. 사용자는 빈 공간 또는 더듬이 표시될 수 있으며, UI 스레드의 두 증상 모두 이동 속도를 따라갈 수 없습니다.

MaxViewport의 위치는 FrameworkElement의 좌표 공간에 보고됩니다. MaxViewportFrameworkElement의 상위 체인에 있는 첫 번째 뷰포트의 좌표 공간으로 변환된 경우 Rect는 첫 번째 뷰포트의 범위 내에 있습니다.

BringIntoViewDistanceX 및 Y

이러한 값은 FrameworkElement가 모든 뷰포트에서 최대로 표시되는 데 얼마나 근접한지를 나타냅니다.

값이 0보다 크지만 ActualWidth / ActualHeight 보다 작으면 요소는 부분적으로 사용자가 볼 수 있는 뷰포트 내에 있습니다. 값이 0이면 FrameworkElement 가 사용자가 볼 수 있는 뷰포트 내에 완전히 포함됩니다.

Z 순서가 더 높은 다른 요소가 FrameworkElement를 계속 차단할 수 있으므로 요소가 사용자에게 표시되는 것을 보장하지는 않습니다.

더 공식적으로 언급된 값은 StartBringIntoView 호출을 충족할 때 FrameworkElement가 변환되는 절대 거리의 합계입니다. 값은 스크롤 컨트롤이 스크롤을 사용하지 않도록 설정된 가능성을 고려하지 않습니다.

<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;
}

동작

  • 부모와 자식의 유효 뷰포트가 모두 변경되면 부모는 자식 앞에 알림을 받습니다.
  • 이벤트는 레이아웃에 참여하는 UI 트리의 요소에 대해서만 발생합니다. 예를 들어 요소가 라이브 트리에 없거나 요소 또는 해당 상위 항목의 Visibility 속성이 Collapsed로 설정된 경우 이 이벤트는 발생하지 않습니다.
  • 유효 뷰포트는 모든 상위 요소에 대한 렌더링 변환을 고려하지만 클리핑의 효과를 고려하지 않습니다(스크롤 컨트롤에서 뷰포트로 등록된 요소의 클립 외).
  • 유효 뷰포트는 Z 순서가 더 높은 다른 요소로 인해 폐색을 고려하지 않습니다.

적용 대상

추가 정보