การจำลองเสมือนของ ItemsControl?


126

ฉันมี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เป็น a ListBoxฉันจะเห็นว่าInitializedเหตุการณ์นั้นดำเนินไปเพียงไม่กี่ครั้งเท่านั้น (ระยะขอบใหญ่มากดังนั้นฉันจึงต้องผ่านบันทึกไม่กี่รายการ) อย่างไรก็ตามเมื่อItemsControlทุกรายการเริ่มต้น

ฉันได้ลองตั้งค่าItemsControlPanelTemplateเป็น a แล้วVirtualizingStackPanelแต่ดูเหมือนจะไม่ช่วยอะไร

คำตอบ:


223

มีจริงมากขึ้นไปกว่าเพียงแค่การใช้งานItemsPanelTemplate VirtualizingStackPanelค่าเริ่มต้นControlTemplateสำหรับItemsControlไม่มี a 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>

(BTW เครื่องมือที่ยอดเยี่ยมสำหรับการดูเทมเพลตการควบคุมเริ่มต้นคือShow Me The Template )

สิ่งที่ควรสังเกต:

คุณต้องตั้งค่าScrollViewer.CanContentScroll="True"ดูเหตุผลที่นี่

VirtualizingStackPanel.VirtualizationMode="Recycling"นอกจากนี้ยังแจ้งให้ทราบว่าผมใส่ ซึ่งจะช่วยลดจำนวนครั้งที่TextBlock_Initializedถูกเรียกไปยัง TextBlocks จำนวนมากที่มองเห็นได้บนหน้าจอ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ UI แบบเสมือนที่นี่

แก้ไข: ลืมระบุสิ่งที่ชัดเจน: ในฐานะทางเลือกอื่นคุณสามารถแทนที่ItemsControlด้วยListBox:) นอกจากนี้ตรวจสอบประสิทธิภาพการเพิ่มประสิทธิภาพนี้ในหน้า MSDNและสังเกตว่าItemsControlไม่มีอยู่ในตาราง "การควบคุมที่ใช้คุณลักษณะประสิทธิภาพ" ซึ่งเป็นสาเหตุ เราจำเป็นต้องแก้ไขเทมเพลตการควบคุม


1
ขอบคุณนั่นคือสิ่งที่ฉันกำลังมองหา! ฉันกำลังมองหาพฤติกรรมการเลือกประเภทที่แตกต่างจากลิสต์บ็อกซ์และในเวลานั้นฉันคิดว่าการควบคุมไอเท็มจะง่ายที่สุด
Rachel

หากการควบคุมรายการนี้ซ้อนกันเพิ่มเติมคุณควรให้ความสูงด้วย มิฉะนั้นโปรแกรมเลื่อนดูจะไม่แสดง
buckley

9
"โปรดสังเกตด้วยว่าฉันใส่ VirtualizingStackPanel.VirtualizationMode = Recycling" ไม่ควรอยู่ในตัวอย่างที่คุณให้มาใช่หรือไม่?
buckley

ไม่ virtualization ยังทำงานเมื่อห่อItemsControlเข้าScrollViewerinstread เพิ่มScrollไปControlTemplate?
สาธิต

1
ด้วยเหตุผลบางประการเนื้อหาของฉันไม่เลื่อนเมื่อฉันเลื่อนแถบเลื่อน มีความคิดอะไรที่อาจทำให้เกิดสิ่งนี้?
mrid

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
ฉันลงคะแนนเนื่องจากโซลูชันไม่สมบูรณ์ คุณต้องใช้ scrollviewer ในเทมเพลตเพื่อเปิดใช้งาน virtualization
Saraf Talukder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.