次の方法で共有


XAML レイアウトを最適化する

重要な API

レイアウトは、UI のビジュアル構造を定義するプロセスです。 XAML でレイアウトを記述するための主なメカニズムは、パネルを介して行われます。これは、パネル内で UI 要素を配置および配置できるコンテナー オブジェクトです。 レイアウトは、CPU 使用率とメモリオーバーヘッドの両方で、XAML アプリの高価な部分になる可能性があります。 XAML アプリのレイアウト パフォーマンスを向上させるために実行できる簡単な手順をいくつか次に示します。

レイアウト構造を減らす

レイアウトパフォーマンスの最大の向上は、UI 要素のツリーの階層構造を簡素化することで得られます。 パネルはビジュアルツリーに存在しますが、構造要素であり、ピクセルを生成する 要素ではありません。これは、ButtonRectangleのようにピクセルを生成する要素ではありません。 通常、非ピクセル生成要素の数を減らすことでツリーを簡略化すると、パフォーマンスが大幅に向上します。

多くの UI は、パネルを入れ子にすることによって実装され、パネルと要素のツリーが深く複雑になります。 パネルを入れ子にするのは便利ですが、多くの場合、より複雑な単一のパネルで同じUIが実現可能です。 1 つのパネルを使用すると、パフォーマンスが向上します。

レイアウト構造を減らすタイミング

最上位ページから入れ子になったパネルを 1 つ減らすなど、簡単な方法でレイアウト構造を縮小しても、目立った効果はありません。

最大のパフォーマンスの向上は、ListView や GridViewなど、UI で繰り返されるレイアウト構造を減らすことによって得られます。 これらの ItemsControl 要素は、何度もインスタンス化される UI 要素のサブツリーを定義する DataTemplateを使用します。 同じサブツリーがアプリ内で何度も重複している場合、そのサブツリーのパフォーマンスが向上すると、アプリの全体的なパフォーマンスに多重度の影響が及びます。

例示

次の UI について考えてみましょう。

フォーム レイアウトの例

これらの例は、同じ UI を実装する 3 つの方法を示しています。 各実装の選択により、画面上のピクセルはほぼ同じになりますが、実装の詳細で大きく異なります。

Option1: 入れ子になった StackPanel 要素

これは最も単純なモデルですが、5 つのパネル要素を使用し、オーバーヘッドが大きくなります。

  <StackPanel>
  <TextBlock Text="Options:" />
  <StackPanel Orientation="Horizontal">
      <CheckBox Content="Power User" />
      <CheckBox Content="Admin" Margin="20,0,0,0" />
  </StackPanel>
  <TextBlock Text="Basic information:" />
  <StackPanel Orientation="Horizontal">
      <TextBlock Text="Name:" Width="75" />
      <TextBox Width="200" />
  </StackPanel>
  <StackPanel Orientation="Horizontal">
      <TextBlock Text="Email:" Width="75" />
      <TextBox Width="200" />
  </StackPanel>
  <StackPanel Orientation="Horizontal">
      <TextBlock Text="Password:" Width="75" />
      <TextBox Width="200" />
  </StackPanel>
  <Button Content="Save" />
</StackPanel>

オプション 2: 単一の グリッド

Grid は複雑さを増しますが、1 つのパネル要素のみを使用します。

<Grid>
  <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <TextBlock Text="Options:" Grid.ColumnSpan="2" />
  <CheckBox Content="Power User" Grid.Row="1" Grid.ColumnSpan="2" />
  <CheckBox Content="Admin" Margin="150,0,0,0" Grid.Row="1" Grid.ColumnSpan="2" />
  <TextBlock Text="Basic information:" Grid.Row="2" Grid.ColumnSpan="2" />
  <TextBlock Text="Name:" Width="75" Grid.Row="3" />
  <TextBox Width="200" Grid.Row="3" Grid.Column="1" />
  <TextBlock Text="Email:" Width="75" Grid.Row="4" />
  <TextBox Width="200" Grid.Row="4" Grid.Column="1" />
  <TextBlock Text="Password:" Width="75" Grid.Row="5" />
  <TextBox Width="200" Grid.Row="5" Grid.Column="1" />
  <Button Content="Save" Grid.Row="6" />
</Grid>

オプション 3: 1 つの RelativePanel:

この単一のパネルは、入れ子になったパネルを使用するよりも少し複雑ですが、グリッドよりも理解と保守が簡単な場合があります。

<RelativePanel>
  <TextBlock Text="Options:" x:Name="Options" />
  <CheckBox Content="Power User" x:Name="PowerUser" RelativePanel.Below="Options" />
  <CheckBox Content="Admin" Margin="20,0,0,0" 
            RelativePanel.RightOf="PowerUser" RelativePanel.Below="Options" />
  <TextBlock Text="Basic information:" x:Name="BasicInformation"
           RelativePanel.Below="PowerUser" />
  <TextBlock Text="Name:" RelativePanel.AlignVerticalCenterWith="NameBox" />
  <TextBox Width="200" Margin="75,0,0,0" x:Name="NameBox"               
           RelativePanel.Below="BasicInformation" />
  <TextBlock Text="Email:"  RelativePanel.AlignVerticalCenterWith="EmailBox" />
  <TextBox Width="200" Margin="75,0,0,0" x:Name="EmailBox"
           RelativePanel.Below="NameBox" />
  <TextBlock Text="Password:" RelativePanel.AlignVerticalCenterWith="PasswordBox" />
  <TextBox Width="200" Margin="75,0,0,0" x:Name="PasswordBox"
           RelativePanel.Below="EmailBox" />
  <Button Content="Save" RelativePanel.Below="PasswordBox" />
</RelativePanel>

これらの例に示すように、同じ UI を実現する方法は多数あります。 パフォーマンス、読みやすさ、保守容易性など、すべてのトレードオフを慎重に検討して選択する必要があります。

単一セルグリッドを使用して UI を重ね合わせる

一般的な UI 要件は、要素が重なり合うレイアウトを用意することです。 通常、パディング、余白、配置、変換は、この方法で要素を配置するために使用されます。 XAML Grid コントロールは、重なる要素のレイアウト パフォーマンスを向上させるために最適化されています。

重要な 改善を確認するためには、単一セルの グリッドを使用してください。 RowDefinitions または ColumnDefinitionsを定義しないでください。

例示

<Grid>
    <Ellipse Fill="Red" Width="200" Height="200" />
    <TextBlock Text="Test" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Center" />
</Grid>

円の上に重ね合わされたテキスト

<Grid Width="200" BorderBrush="Black" BorderThickness="1">
    <TextBlock Text="Test1" HorizontalAlignment="Left" />
    <TextBlock Text="Test2" HorizontalAlignment="Right" />
</Grid>

グリッド内の 2 つのテキスト ブロック

パネルの組み込みの境界線プロパティを使用する

GridStackPanelRelativePanel、および ContentPresenter コントロールには組み込みの罫線プロパティがあり、Border 要素を XAML に追加せずに境界線を描画できます。 組み込みの境界線をサポートする新しいプロパティは、BorderBrushBorderThicknessCornerRadius、および Paddingです。 これらはそれぞれ DependencyPropertyであるため、バインディングとアニメーションで使用できます。 これらは、別の Border 要素の完全な置換として設計されています。

UI にこれらのパネルの周囲に Border 要素がある場合は、代わりに組み込みの境界線を使用します。これにより、アプリのレイアウト構造に余分な要素が保存されます。 前述のように、これは、特に UI を繰り返す場合に大幅な節約になる可能性があります。

例示

<RelativePanel BorderBrush="Red" BorderThickness="2" CornerRadius="10" Padding="12">
    <TextBox x:Name="textBox1" RelativePanel.AlignLeftWithPanel="True"/>
    <Button Content="Submit" RelativePanel.Below="textBox1"/>
</RelativePanel>

SizeChanged イベントを使用してレイアウトの変更に応答する

FrameworkElement クラスは、レイアウトの変更に応答するための2つの同様なイベントを提供します。「LayoutUpdated」と「SizeChanged」です。 これらのイベントのいずれかを使用して、レイアウト中に要素のサイズが変更されたときに通知を受け取ることがあります。 2 つのイベントのセマンティクスは異なり、それらを選択する際に重要なパフォーマンスに関する考慮事項があります。

パフォーマンスを向上させるには、SizeChanged が常に適切な選択肢です。 SizeChanged には直感的なセマンティクスがあります。 レイアウト中に、FrameworkElement のサイズが更新されたときに発生します。

LayoutUpdated はレイアウト中にも発生しますが、グローバル セマンティクスを持ち、要素が更新されるたびにすべての要素で発生します。 通常、イベント ハンドラーでのみローカル処理を行います。その場合、コードは必要以上に頻繁に実行されます。 LayoutUpdated を使用するのは、サイズを変更せずに要素の位置が変更されるタイミングを知る必要がある場合のみです (一般的ではありません)。

パネルの中から選択する

パフォーマンスは、通常、個々のパネルを選択する際の考慮事項ではありません。 通常、この選択は、実装する UI に最も近いレイアウト動作を提供するパネルを検討することによって行われます。 たとえば、GridStackPanel、RelativePanelのいずれかを選択する場合は、実装のメンタル モデルに最も近いマッピングを提供するパネルを選択する必要があります。

すべての XAML パネルは優れたパフォーマンスのために最適化されており、すべてのパネルは同様の UI に対して同様のパフォーマンスを提供します。