次の方法で共有


オブジェクトの有効期間イベント (WPF .NET)

Microsoft .NET マネージド コード内のすべてのオブジェクトは、ライフタイム中に 作成使用、および 破棄 のステージを通ります。 Windows Presentation Foundation (WPF) は、有効期間イベントを発生させることで、オブジェクト上で発生するこれらのステージの通知を提供します。 WPF フレームワーク レベルの要素 (ビジュアル オブジェクト) の場合、WPF は InitializedLoaded、および Unloaded 有効期間イベントを実装します。 開発者は、要素を含む分離コード操作のフックとして、これらの有効期間イベントを使用できます。 この記事では、ビジュアル オブジェクトの有効期間イベントについて説明し、ウィンドウ要素、ナビゲーション ホスト、またはアプリケーション オブジェクトに特に適用されるその他の有効期間イベントについて説明します。

前提 条件

この記事では、WPF 要素レイアウトをツリーとして概念化する方法に関する基本的な知識と、ルーティング イベントの概要読んだことを前提としています。 この記事の例に従うには、拡張アプリケーション マークアップ言語 (XAML) に慣れている場合や、WPF アプリケーションを記述する方法を理解している場合に役立ちます。

ビジュアル オブジェクトの有効期間イベント

WPF フレームワーク レベルの要素は、FrameworkElement または FrameworkContentElementから派生します。 InitializedLoaded、および Unloaded 有効期間イベントは、すべての WPF フレームワーク レベルの要素に共通です。 次の例は、主に XAML で実装されている要素ツリーを示しています。 XAML は、入れ子になった要素を含む親 Canvas 要素を定義します。各要素は XAML 属性構文を使用して、InitializedLoaded、および Unloaded 有効期間イベント ハンドラーをアタッチします。

<Canvas x:Name="canvas">
    <StackPanel x:Name="outerStackPanel" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler">
        <custom:ComponentWrapper x:Name="componentWrapper" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler">
            <TextBox Name="textBox1" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler" />
            <TextBox Name="textBox2" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler" />
        </custom:ComponentWrapper>
    </StackPanel>
    <Button Content="Remove canvas child elements" Click="Button_Click"/>
</Canvas>

XAML 要素の 1 つはカスタム コントロールであり、コードビハインドで有効期間イベント ハンドラーを割り当てる基底クラスから派生します。

public partial class MainWindow : Window
{
    public MainWindow() => InitializeComponent();

    // Handler for the Initialized lifetime event (attached in XAML).
    private void InitHandler(object sender, System.EventArgs e) => 
        Debug.WriteLine($"Initialized event on {((FrameworkElement)sender).Name}.");

    // Handler for the Loaded lifetime event (attached in XAML).
    private void LoadHandler(object sender, RoutedEventArgs e) => 
        Debug.WriteLine($"Loaded event on {((FrameworkElement)sender).Name}.");

    // Handler for the Unloaded lifetime event (attached in XAML).
    private void UnloadHandler(object sender, RoutedEventArgs e) =>
        Debug.WriteLine($"Unloaded event on {((FrameworkElement)sender).Name}.");

    // Remove nested controls.
    private void Button_Click(object sender, RoutedEventArgs e) => 
        canvas.Children.Clear();
}

// Custom control.
public class ComponentWrapper : ComponentWrapperBase { }

// Custom base control.
public class ComponentWrapperBase : StackPanel
{
    public ComponentWrapperBase()
    {
        // Assign handler for the Initialized lifetime event (attached in code-behind).
        Initialized += (object sender, System.EventArgs e) => 
            Debug.WriteLine($"Initialized event on componentWrapperBase.");

        // Assign handler for the Loaded lifetime event (attached in code-behind).
        Loaded += (object sender, RoutedEventArgs e) => 
            Debug.WriteLine($"Loaded event on componentWrapperBase.");

        // Assign handler for the Unloaded lifetime event (attached in code-behind).
        Unloaded += (object sender, RoutedEventArgs e) => 
            Debug.WriteLine($"Unloaded event on componentWrapperBase.");
    }
}

/* Output:
Initialized event on textBox1.
Initialized event on textBox2.
Initialized event on componentWrapperBase.
Initialized event on componentWrapper.
Initialized event on outerStackPanel.

Loaded event on outerStackPanel.
Loaded event on componentWrapperBase.
Loaded event on componentWrapper.
Loaded event on textBox1.
Loaded event on textBox2.

Unloaded event on outerStackPanel.
Unloaded event on componentWrapperBase.
Unloaded event on componentWrapper.
Unloaded event on textBox1.
Unloaded event on textBox2.
*/
Partial Public Class MainWindow
    Inherits Window

    Public Sub New()
        InitializeComponent()
    End Sub

    ' Handler for the Initialized lifetime event (attached in XAML).
    Private Sub InitHandler(sender As Object, e As EventArgs)
        Debug.WriteLine($"Initialized event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    ' Handler for the Loaded lifetime event (attached in XAML).
    Private Sub LoadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine($"Loaded event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    ' Handler for the Unloaded lifetime event (attached in XAML).
    Private Sub UnloadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine($"Unloaded event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        ' Remove nested controls.
        canvas.Children.Clear()
    End Sub
End Class

' Custom control.
Public Class ComponentWrapper
    Inherits ComponentWrapperBase
End Class

' Custom base control.
Public Class ComponentWrapperBase
    Inherits StackPanel

    Public Sub New()
        ' Attach handlers for the lifetime events.
        AddHandler Initialized, AddressOf InitHandler
        AddHandler Loaded, AddressOf LoadHandler
        AddHandler Unloaded, AddressOf UnloadHandler
    End Sub

    ' Handler for the Initialized lifetime event (attached in code-behind).
    Private Sub InitHandler(sender As Object, e As EventArgs)
        Debug.WriteLine("Initialized event on componentWrapperBase.")
    End Sub

    ' Handler for the Loaded lifetime event (attached in code-behind).
    Private Sub LoadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine("Loaded event on componentWrapperBase.")
    End Sub

    ' Handler for the Unloaded lifetime event (attached in code-behind).
    Private Sub UnloadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine("Unloaded event on componentWrapperBase.")
    End Sub
End Class

'Output:
'Initialized event on textBox1.
'Initialized event on textBox2.
'Initialized event on componentWrapperBase.
'Initialized event on componentWrapper.
'Initialized event on outerStackPanel.

'Loaded event on outerStackPanel.
'Loaded event on componentWrapperBase.
'Loaded event on componentWrapper.
'Loaded event on textBox1.
'Loaded event on textBox2.

'Unloaded event on outerStackPanel.
'Unloaded event on componentWrapperBase.
'Unloaded event on componentWrapper.
'Unloaded event on textBox1.
'Unloaded event on textBox2.

プログラム出力には、各ツリー オブジェクトでの InitializedLoaded、および Unloaded の有効期間イベントの呼び出しの順序が表示されます。 これらのイベントは、各ツリー オブジェクトで発生する順序で、次のセクションで説明します。

初期化された有効期間イベント

WPF イベント システムは、要素に対して Initialized イベントを発生させます。

  • 要素のプロパティが設定されている場合。
  • オブジェクトがコンストラクターの呼び出しによって初期化されるのと同じ頃。

Panel.Childrenなどの一部の要素プロパティには、子要素を含めることができます。 親要素は、子要素が初期化されるまで初期化を報告できません。 そのため、プロパティ値は、要素ツリー内で最も深く入れ子になった要素から始まり、その後にアプリケーション ルートまでの連続する親要素が設定されます。 Initialized イベントは要素のプロパティが設定されたときに発生するため、そのイベントは、マークアップで定義されている最も深く入れ子になった要素で最初に呼び出され、その後にアプリケーション ルートまでの連続する親要素が呼び出されます。 オブジェクトがコード ビハインドで動的に作成されると、その初期化が順序外になる可能性があります。

WPF イベント システムは、要素ツリー内のすべての要素が初期化されるのを待ってから、要素の Initialized イベントを発生させるわけではありません。 そのため、任意の要素の Initialized イベント ハンドラーを記述するときは、論理ツリーまたはビジュアル ツリー内の周囲の要素 (特に親要素) が作成されていない可能性があることに注意してください。 または、メンバー変数とデータ バインディングが初期化されていない可能性があります。

手記

Initialized イベントが要素で発生すると、動的リソースやバインドなどの要素の式の使用法は評価されなくなります。

読み込まれた有効期間イベント

WPF イベント システムは、要素に対して Loaded イベントを発生させます。

  • 要素を含む論理ツリーが完了し、プレゼンテーション ソースに接続されている場合。 プレゼンテーション ソースは、ウィンドウ ハンドル (HWND) とレンダリング サーフェイスを提供します。
  • 他のプロパティや直接定義されたデータ ソースなど、ローカル ソースへのデータ バインディングが完了した場合。
  • レイアウト システムがレンダリングに必要なすべての値を計算した後。
  • 最終的なレンダリングの前。

論理ツリー内の "すべての" 要素が読み込まれるまで、要素ツリーのどの要素でも Loaded イベントは発生しません。 WPF イベント システムは、最初に要素ツリーのルート要素に対して Loaded イベントを発生させ、その後、最も深い入れ子になった要素まで、順次各子要素に対してイベントを発生させます。 このイベントは、ルーティング イベント トンネリングに似ていますが、 イベントは、ある要素から別の要素にイベント データを伝達しないため、イベントを処理済みとしてマークしても効果はありません。

手記

WPF イベント システムでは、Loaded イベントの前に非同期データ バインディングが完了したことを保証できません。 非同期データ バインディングは、外部ソースまたは動的ソースにバインドされます。

読み込まれていない有効期間イベント

WPF イベント システムは、要素に対して Unloaded イベントを発生させます。

  • そのプレゼンテーション ソースを削除したとき、または
  • そのビジュアルの親を削除したとき

WPF イベント システムは、まず要素ツリーのルート要素で Unloaded イベントを発生させ、次に最も深く入れ子になった要素まで、順次すべての子要素でイベントを発生させます。 このイベントはルーティング イベント トンネリングに似ていますが、 イベントは要素間でイベント データを伝達しないため、イベントを処理済みとしてマークしても効果はありません。

ある要素に対して Unloaded イベントが発生すると、その要素の要素や、論理ツリーやビジュアル ツリーで上位の要素が既に "未設定" にされている可能性があります。 Unset は、要素のデータ バインディング、リソース参照、およびスタイルが、通常のランタイム値または最後の既知の実行時値に設定されなくなったことを意味します。

その他の有効期間イベント

有効期間イベントの観点からは、WPF オブジェクトには、一般的な要素、ウィンドウ要素、ナビゲーション ホスト、アプリケーション オブジェクトの 4 種類があります。 InitializedLoaded、および Unloaded 有効期間イベントは、すべてのフレームワーク レベルの要素に適用されます。 その他の有効期間イベントは、ウィンドウ要素、ナビゲーション ホスト、またはアプリケーション オブジェクトに特に適用されます。 その他の有効期間イベントの詳細については、以下を参照してください。

  • Application オブジェクトのアプリケーション管理の概要。
  • Window 要素の WPF ウィンドウ の概要。
  • PageNavigationWindow、および Frame 要素のナビゲーションの概要。

関連項目