ItemsControlを仮想化しますか?


125

私はしている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が、それは役に立たないようです。

回答:


219

実際には、単にItemsPanelTemplate使用するだけではありませんVirtualizingStackPanel。のデフォルトControlTemplateには、仮想化の鍵となるがありItemsControlませんScrollViewer。のデフォルトのコントロールテンプレートにItemsControl(テンプレートとしてのコントロールテンプレートを使用して)追加すると、ListBox次のようになります。

<ItemsControl ItemsSource="{Binding AccountViews.Tables[0]}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Initialized="TextBlock_Initialized"
                 Text="{Binding Name}" />
    </DataTemplate>
  </ItemsControl.ItemTemplate>

  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel IsVirtualizing="True"
                              VirtualizationMode="Recycling" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <Border BorderThickness="{TemplateBinding BorderThickness}"
              BorderBrush="{TemplateBinding BorderBrush}"
              Background="{TemplateBinding Background}">
        <ScrollViewer CanContentScroll="True" 
                      Padding="{TemplateBinding Padding}"
                      Focusable="False">
          <ItemsPresenter />
        </ScrollViewer>
      </Border>
    </ControlTemplate>
  </ItemsControl.Template>
</ItemsControl>

(ちなみに、デフォルトのコントロールテンプレートを確認するための優れたツールはShow Me The Templateです

注目すべきこと:

を設定する必要があります。理由ScrollViewer.CanContentScroll="True"については、こちらを参照してください。

私が置いVirtualizingStackPanel.VirtualizationMode="Recycling"たことにも注意してください。これにより、TextBlock_Initialized呼び出される回数が減りますが、画面に多くのTextBlockが表示されます。UI仮想化の詳細については、こちらをご覧ください

EDIT:明白なことを述べることを忘れ:代替ソリューションとして、あなただけ置き換えることができItemsControlListBox、このチェックアウト、また:) MSDNのページのパフォーマンスの最適化と予告ItemsControl理由でテーブルを「パフォーマンス機能を実装コントロール」ではありませんが、コントロールテンプレートを編集する必要があります。


1
ありがとう、それはまさに私が探していたものです!リストボックスとは異なる種類の選択動作を探していましたが、当時はアイテムコントロールを使用するのが最も簡単だと思いました。
レイチェル

このitemscontrolがさらにネストされている場合は、高さも指定する必要があります。それ以外の場合、scrollviewerは表示されません。
バックリー2014

9
「VirtualizingStackPanel.VirtualizationMode = Recyclingを置いたことにも注意してください」。あなたが提供するサンプルにあるはずではありませんか?
Buckley、2015年

仮想化はItemsControlScrollViewerinstreadに追加Scrollするときにも機能しControlTemplateますか?
デモ

@DavidNソリューションのどこに、またはどのように列ヘッダーを配置できますか?
Ozkan 2017年

37

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を使用するという提案は好きではありません。必ずしも必要としない場所で行を選択できるからです。


-3

デフォルトItemsPanelはでないだけですVirtualizingStackPanel。変更する必要があります:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

8
解決策が不完全なため、私は投票に応じません。仮想化を有効にするには、テンプレートでスクロールビューアを使用する必要があります。
Saraf Talukder、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.