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 を含むすべての既知のビューポートの交差部分です。 重なり合わない 2 つ以上のビューポート (別の ScrollViewer 内に入れ子になった ScrollViewer など) がある場合、EffectiveViewport は空の Rect になります

注意

スクロール コントロールのビューポートがフレームワークに 認識 されるようにするには、コントロールが UIElement.RegisterAsScrollPort メソッドを使用して以前に登録しておく必要があります。 フレームワークは、有効なビューポートを決定するときに、登録済み要素の Clip を使用します。

スクロール コントロールのビューポートが変更された場合は、 InvalidateViewport メソッドを呼び出して、ビューポートが変更されたこと、および有効なビューポートをリッスンするサブ要素に変更を通知する必要があることをフレームワークに通知する必要があります。

EffectiveViewport は、FrameworkElement の座標空間に指定されます。 ビューポート Rect を使用して TransformToVisual を実行する必要はありません。

1 つの要素を含む 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 は、次の 2 つを表します。

  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 オーダーが高いため、オクルージョンは考慮されません。

適用対象

こちらもご覧ください