Ảo hóa một ItemControl?


125

Tôi có ItemsControlmột danh sách chứa dữ liệu mà tôi muốn ảo hóa, tuy nhiên VirtualizingStackPanel.IsVirtualizing="True"dường như không hoạt động với một ItemsControl.

Đây thực sự là trường hợp hay có một cách khác để làm điều này mà tôi không nhận thức được?

Để kiểm tra tôi đã sử dụng khối mã sau:

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

Nếu tôi thay đổi ItemsControlthành a ListBox, tôi có thể thấy rằng Initializedsự kiện chỉ diễn ra trong một vài lần (lợi nhuận rất lớn chỉ vì vậy tôi chỉ phải trải qua một vài bản ghi), tuy nhiên vì ItemsControlmọi mục đều được khởi tạo.

Tôi đã thử cài đặt ItemsControlPanelTemplatethành một VirtualizingStackPanelnhưng điều đó dường như không có ích.

Câu trả lời:


219

Thực tế có nhiều thứ hơn là chỉ ItemsPanelTemplatesử dụng VirtualizingStackPanel. Mặc định ControlTemplatecho ItemsControlkhông có a ScrollViewer, đó là chìa khóa để ảo hóa. Thêm vào mẫu điều khiển mặc định cho ItemsControl(sử dụng mẫu điều khiển ListBoxlàm mẫu) sẽ cho chúng ta những điều sau:

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

(BTW, một công cụ tuyệt vời để xem các mẫu điều khiển mặc định là Show Me The Template )

Những điều cần chú ý:

Bạn phải thiết lập ScrollViewer.CanContentScroll="True", xem ở đây để biết lý do tại sao.

Cũng thông báo rằng tôi đặt VirtualizingStackPanel.VirtualizationMode="Recycling". Điều này sẽ giảm số lần TextBlock_Initializedđược gọi đến tuy nhiên nhiều TextBlocks hiển thị trên màn hình. Bạn có thể đọc thêm về ảo hóa UI ở đây .

EDIT: Quên nêu rõ ràng: như một giải pháp thay thế, bạn chỉ có thể thay thế ItemsControlbằng ListBox:) Ngoài ra, hãy xem Hiệu suất tối ưu hóa này trên trang MSDN và lưu ý rằng ItemsControlkhông có trong bảng "Điều khiển thực hiện các tính năng hiệu suất", đó là lý do tại sao chúng ta cần chỉnh sửa mẫu điều khiển.


1
Cảm ơn bạn, đó chính xác là thứ mà tôi đang tìm kiếm! Tôi đang tìm kiếm một loại hành vi lựa chọn khác với hộp danh sách và tại thời điểm đó tôi nghĩ rằng nó sẽ dễ thực hiện nhất với điều khiển vật phẩm.
Rachel

Nếu vật phẩm này được lồng thêm, bạn cũng nên cho nó chiều cao. Nếu không, trình xem cuộn không được hiển thị.
buckley

9
"Cũng lưu ý rằng tôi đặt VirtualizingStackPanel.VirtualizationMode = Tái chế". Nó không phải là trong mẫu bạn cung cấp?
buckley

Liệu ảo hóa cũng hoạt động khi bọc ItemsControlvào đầu vào ScrollViewerthêm Scrollvào ControlTemplate?
bản demo

@DavidN Tôi có thể đặt tiêu đề cột ở đâu hoặc làm thế nào?
Ozkan

37

Dựa trên câu trả lời của DavidN, đây là một phong cách bạn có thể sử dụng trên ItemControl để ảo hóa nó:

<!--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>

Tôi không thích đề xuất sử dụng ListBox vì chúng cho phép lựa chọn các hàng mà bạn không nhất thiết muốn nó.


-3

Nó chỉ là mặc định ItemsPanelkhông phải là một VirtualizingStackPanel. Bạn cần thay đổi nó:

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

8
Tôi không bình chọn nó vì giải pháp không đầy đủ. Bạn cần sử dụng một trình xem cuộn trong mẫu để kích hoạt ảo hóa.
Saraf Talukder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.