ItemsControl, VirtualizingStackPanel and ScrollVie

2020-08-26 05:23发布

问题:

I want to display a important list of items using an ItemsControl.

The reason why I'm using an ItemsControl is that the DataTemplate is much more complex in the application I'm working on: The sample code provided only reflects the sizing problem I have.

I would like :

  • the ItemsControl to be virtualized because there is many items to display
  • its size to expand to its parent container automatically (the Grid)

    <Grid>
        <ItemsControl x:Name="My" ItemsSource="{Binding Path=Names}">
            <ItemsControl.Template>
                <ControlTemplate>
                    <StackPanel>
                        <StackPanel>
                            <TextBlock Text="this is a title" FontSize="15" />
                            <TextBlock Text="This is a description" />
                        </StackPanel>
                        <ScrollViewer CanContentScroll="True" Height="400px">
                            <VirtualizingStackPanel IsItemsHost="True" />
                        </ScrollViewer>
                    </StackPanel>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
    

The code behind is :

public partial class Page1: Page
{
    public List<string> Names { get; set; }
    public Page1()
    {
        InitializeComponent();

        Names = new List<string>();
        for(int i = 0; i < 10000; i++)
            Names.Add("Name : " + i);

        My.DataContext = this;
    }
}

As I force the ScrollViewer height to 400px, ItemsControl virtualization works as I expect: The ItemsControl displays the list very quickly, regardless of how many items it contains.

However, if I remove Height="400px", the list will expand its height to display the whole list, regardless its parent container height. Worse: it appears behind its container.

Putting a scrollviewer around the ItemsControl gives the expected visual result, but the virtualization goes away and the list takes too much time to display.

How can I achieve both automatic height expansion and virtualization of my ItemsControl ?

回答1:

The problem is in the ItemsControl.Template: you use StackPanel there, which gives her children as much height as they want. Replace it to something like

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel>
        <TextBlock Text="this is a title" FontSize="15" />
        <TextBlock Text="This is a description" />
    </StackPanel>
    <ScrollViewer CanContentScroll="True" Grid.Row="1">
        <VirtualizingStackPanel />
    </ScrollViewer>
</Grid>

And it should work fine.

Hope it helps.