仮想化するデータのリストを含むItemsControl
がありますが、VirtualizingStackPanel.IsVirtualizing="True"
はItemsControl
では機能しないようです。
これは本当にそうですか、それとも私が知らない別の方法がありますか?
テストするために、次のコードブロックを使用しています。
<ItemsControl ItemsSource="{Binding Path=AccountViews.Tables[0]}"
VirtualizingStackPanel.IsVirtualizing="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Initialized="TextBlock_Initialized"
Margin="5,50,5,50" Text="{Binding Path=Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ItemsControl
をListBox
に変更すると、Initialized
イベントはほんの数回しか実行されないことがわかります(大きなマージンがあるので、ただし、ItemsControl
としてすべてのアイテムが初期化されます。
ItemsControlPanelTemplate
をVirtualizingStackPanel
に設定しようとしましたが、それは役に立たないようです。
実際には、ItemsPanelTemplate
にVirtualizingStackPanel
を使用させるだけではありません。 ControlTemplate
のデフォルトのItemsControl
には、仮想化の鍵となるScrollViewer
がありません。 ItemsControl
のデフォルトのコントロールテンプレートに追加すると(テンプレートとしてListBox
のコントロールテンプレートを使用)、次のようになります。
<ItemsControl
VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.CanContentScroll="True"
ItemsSource="{Binding Path=AccountViews.Tables[0]}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock
Initialized="TextBlock_Initialized"
Text="{Binding Path=Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer
Padding="{TemplateBinding Control.Padding}"
Focusable="False">
<ItemsPresenter
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
(ところで、デフォルトのコントロールテンプレートを見るのに最適なツールは Show Me The Template )
注目すべきこと:
ScrollViewer.CanContentScroll="True"
を設定する必要があります。理由については here を参照してください。
また、VirtualizingStackPanel.VirtualizationMode="Recycling"
と入力していることに注意してください。これにより、TextBlock_Initialized
が呼び出される回数が減りますが、多くのTextBlockが画面に表示されます。 UI仮想化の詳細については、こちらをご覧ください こちら .
編集:明白なことを忘れました:代替ソリューションとして、ItemsControl
をListBox
に置き換えることができます:)また、これをチェックしてください MSDNページのパフォーマンスの最適化 とItemsControl
は「パフォーマンス機能を実装するコントロール」テーブルにないことに注意してください。これが、コントロールテンプレートを編集する必要がある理由です。
DavidNの答えに基づいて、ItemsControlで仮想化するために使用できるスタイルを次に示します。
<!--Virtualised ItemsControl-->
<Style x:Key="ItemsControlVirtualizedStyle" TargetType="ItemsControl">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True"
>
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ListBoxを使用することをお勧めしません。リストボックスを使用すると、必ずしも必要ではない行を選択できます。