2010-05-06 87 views
103

我有一個ItemsControl包含我想要虛擬化的數據列表,但VirtualizingStackPanel.IsVirtualizing="True"似乎不適用於ItemsControl虛擬化一個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> 

如果我改變ItemsControlListBox,我可以看到Initialized事件只運行的時間屈指可數(鉅額利潤所以我只需要通過幾條記錄),但是作爲ItemsControl,每個項目都會被初始化。

我曾嘗試將ItemsControlPanelTemplate設置爲VirtualizingStackPanel,但這似乎沒有幫助。

回答

178

這事實上它不僅僅是使ItemsPanelTemplate使用VirtualizingStackPanel得多。 ItemsControl的默認ControlTemplate沒有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的次數,但是很多TextBlocks在屏幕上可見。您可以閱讀關於用戶界面虛擬化here 的更多信息。

編輯:忘了不言自明的:作爲一個替代的解決方案,你可以用ListBox :) 更換ItemsControl此外,檢查出這個Optimizing Performance on MSDN page並注意ItemsControl是不是在「控件實現性能特點」表這就是我們需要編輯控件模板的原因。

+1

謝謝你,那就是我正在尋找的那種東西!我正在尋找一種不同於列表框的選擇行爲,並且當時我認爲這對於項目控件來說是最簡單的。 – Rachel 2010-05-07 12:20:13

+0

ListView也適用於此。 – 2010-08-10 20:20:42

+0

如果這個itemcontrol進一步嵌套,你應該給它一個高度。否則,不會顯示滾動查看器。 – buckley 2014-09-24 21:31:02

-3

這只是默認的ItemsPanel不是VirtualizingStackPanel。你需要改變它:

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

謝謝,但我已經試過這個,它沒有工作。 – Rachel 2010-05-07 12:22:38

+6

由於解決方案不完整,我對此投了棄權票。您需要在模板中使用滾動查看器來啓用虛擬化。 – 2015-06-02 13:12:48

22

大廈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> 

我不喜歡這個建議,使用一個列表框,因爲它們允許在那裏你行的選擇不一定需要它。