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 方法注册它。 框架在确定有效视区时使用已注册元素的 剪辑

滚动控件的视区更改时,它必须调用其 InvalidateViewport 方法,以通知框架其视区已更改,并且侦听有效视区的任何子元素都需要收到更改通知。

EffectiveViewportFrameworkElement 的坐标空间中提供。 无需使用视区 Rect 执行 TransformToVisual

在包含单个元素的 ScrollViewer 的简单方案中,EffectiveViewportChanged 事件提供类似于 ViewChanged 事件的视区更新。 main区别在于,在布局的排列传递之后引发 EffectiveViewportChanged 事件。

例如,此 ...

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

...提供与此类似的视区信息...

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

MaxViewport

MaxViewport 类似于 EffectiveViewport,但它不是表示已知视口的简单交集,而是表示视口的交集,就好像每个视区都已进入任何外部视口的视图一样。 生成的 Rect 表示两项内容:

  1. 根据当前视区大小) ,EffectiveViewport 可以 (的最大大小,以及
  2. 相对于 FrameworkElement 的最大有效视区的位置。

此信息可用于衡量 FrameworkElement 应预先生成的内容,以在滚动到视图中 之前 可能填充视区的位置和内容量。

注意

通过直接输入(如触摸或笔)滚动由系统在单独的进程中进行处理。 默认情况下,滚动以异步方式处理到 UI 线程。 由于元素创建的固有成本,执行虚拟化的控件可能需要在进入视区之前预先生成内容。

延迟所有内容准备,直到进入视图可能会导致用户滚动体验不佳。 用户可能会看到空白或断断续续,这两种症状都是 UI 线程无法跟上平移速度的症状。

MaxViewport 的位置在 FrameworkElement 的坐标空间中报告。 如果将 MaxViewport 转换为 FrameworkElement 的上级链中第一个视区的坐标空间, 则 Rect 将位于第一个视区的边界内。

BringIntoViewDistanceX 和 Y

这些值指示 FrameworkElement 在其所有视区中如何最接近地可见。

如果值大于零,但小于 ActualWidth / ActualHeight ,则元素部分位于用户可见视区内。 如果值为零,则 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 顺序较高,有效视区不考虑遮挡。

适用于

另请参阅