WPF アプリケーションの設計は、レイアウトの計算やオブジェクト参照の検証に不要なオーバーヘッドを生み出すことで、そのパフォーマンスに影響を与える可能性があります。 オブジェクトの構築 (特に実行時) は、アプリケーションのパフォーマンス特性に影響を与える可能性があります。
このトピックでは、これらの領域のパフォーマンスに関する推奨事項について説明します。
レイアウト
"レイアウト パス" という用語は、Panel 派生オブジェクトの子のコレクションのメンバーを測定および配置して、それらを画面上に描画するプロセスを表します。 レイアウト パスは数学的に集中的なプロセスであり、コレクション内の子の数が多いほど、必要な計算の数が多くなります。 たとえば、コレクション内の子 UIElement オブジェクトがその位置を変更するたびに、レイアウト システムによって新しいパスをトリガーする可能性があります。 オブジェクトの特性とレイアウト動作の間に密接な関係があるため、レイアウト システムを呼び出すことができるイベントの種類を理解することが重要です。 レイアウト パスの不要な呼び出しを可能な限り減らすことで、アプリケーションのパフォーマンスが向上します。
レイアウト システムは、コレクションの子メンバーごとに、測定パスと配置パスという 2 つのパスを実行します。 各子オブジェクトは、独自の特定のレイアウト動作を提供するために、Measure メソッドと Arrange メソッドの独自のオーバーライドされた実装を提供します。 最も単純なレイアウトは、要素のサイズ変更、配置、画面上での描画につながる再帰システムです。
子 UIElement オブジェクトは、最初にそのコア プロパティを測定することによって、レイアウト プロセスを開始します。
FrameworkElement、Width、Heightなど、サイズに関連するオブジェクトの Margin プロパティが評価されます。
Panelの Dock プロパティや、DockPanelの Orientation プロパティなど、StackPanel固有のロジックが適用されます。
すべての子オブジェクトが測定された後、コンテンツが配置されます。
子オブジェクトのコレクションが画面に描画されます。
次のいずれかのアクションが発生すると、レイアウト パス プロセスが再度呼び出されます。
子オブジェクトがコレクションに追加されます。
LayoutTransform が子オブジェクトに適用されます。
UpdateLayout メソッドは、子オブジェクトに対して呼び出されます。
測定パスや配置パスに影響を与えるものとしてメタデータでマークされている依存関係プロパティの値が変更された場合。
可能な限り最も効率的なパネルを使用する
レイアウト プロセスの複雑さは、使用する Panel派生要素のレイアウト動作に直接基づいています。 たとえば、Grid コントロールや StackPanel コントロールは、Canvas コントロールよりもはるかに多くの機能を提供します。 この機能の増加に対する価格は、パフォーマンス コストの増加です。 ただし、Grid コントロールで提供される機能が不要な場合は、Canvas やカスタム パネルなど、コストの低い代替手段を使用する必要があります。
詳細については、「パネルの概要」を参照してください。
RenderTransform を置き換える代わりに更新する
Transform プロパティの値として置き換えるのではなく、RenderTransform を更新できる場合があります。 これは、アニメーションを含むシナリオで特に当てはまります。 既存の Transformを更新することで、不要なレイアウト計算を開始しないようにします。
ツリー Top-Down を構築する
ノードが論理ツリーに追加または削除されると、ノードの親とそのすべての子でプロパティの無効化が発生します。 その結果、既に検証済みのノードで不要な無効化のコストが発生しないように、常にトップダウン構築パターンに従う必要があります。 次の表は、ツリーが 150 レベルの深さで、各レベルに1つのTextBlockとDockPanelがある場合に、トップダウン構築とボトムアップ構築の間の実行速度の違いを示しています。
アクション | ツリー構築(ミリ秒単位) | レンダリング - ツリーの作成を含む (ミリ秒) |
---|---|---|
ボトムアップ | 366 | 454 |
トップダウン | 11 | 96 |
次のコード例では、ツリーを上から下に作成する方法を示します。
private void OnBuildTreeTopDown(object sender, RoutedEventArgs e)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = "Default";
DockPanel parentPanel = new DockPanel();
DockPanel childPanel;
myCanvas.Children.Add(parentPanel);
myCanvas.Children.Add(textBlock);
for (int i = 0; i < 150; i++)
{
textBlock = new TextBlock();
textBlock.Text = "Default";
parentPanel.Children.Add(textBlock);
childPanel = new DockPanel();
parentPanel.Children.Add(childPanel);
parentPanel = childPanel;
}
}
Private Sub OnBuildTreeTopDown(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim textBlock As New TextBlock()
textBlock.Text = "Default"
Dim parentPanel As New DockPanel()
Dim childPanel As DockPanel
myCanvas.Children.Add(parentPanel)
myCanvas.Children.Add(textBlock)
For i As Integer = 0 To 149
textBlock = New TextBlock()
textBlock.Text = "Default"
parentPanel.Children.Add(textBlock)
childPanel = New DockPanel()
parentPanel.Children.Add(childPanel)
parentPanel = childPanel
Next i
End Sub
論理ツリーの詳細については、「WPFの
こちらも参照ください
.NET Desktop feedback