Expander, Grid & ListBox = Нет виртуализации - PullRequest
3 голосов
/ 23 июля 2011

У меня есть ListBox, внутри Grid, внутри Expander.ListBox связан с IList.

Когда я впервые раскрываю элемент управления Expander, ListBox обрабатывает все элементы в IList (которые могут быть тысячами) вместо обработки только тех элементов, которые будутвиден на экране.

Если, однако, я фиксирую высоту элемента управления ListBox, он ведет себя как положено и обращается только к тем элементам в IList, которые будут видны.

По сути, виртуализация не работает, хотя яПолагаю, что это в большей степени связано с тем, что ListBox не может определить высоту при подготовке элементов контента.

XAML в основном выглядит следующим образом (некоторые вещи удалены для упрощения) ...

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Expander ExpandDirection="Right"
              Grid.Column="0"
              Grid.Row="0"
              Grid.RowSpan="2"
              Header="Documents"
              IsExpanded="False">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="50" />
                </Grid.RowDefinitions>
            </Grid>
            <ListBox Name="listBox"
                     Grid.Row="1"
                     ItemsSource="{Binding Path=Items}"
                     SelectedIndex="{Binding Path=SelectedIndex}"
                     SelectedItem="{Binding Path=SelectedItem}"
                     SelectionMode="Single"
                     Width="250">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto" />
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Column="0"
                                       Style="{StaticResource prompt}">
                                <TextBlock.Text>
                                    <MultiBinding StringFormat="{}{0}{1:00000}">
                                        <Binding Path="..."
                                                 FallbackValue="0" />
                                        <Binding Path="..." />
                                    </MultiBinding>
                                </TextBlock.Text></TextBlock>
                            <TextBlock Grid.Column="1"
                                       Style="{StaticResource prompt}">
                                <TextBlock.Text>
                                    <Binding Path="ItemCount"
                                             StringFormat="{}{0} Items"
                                             FallbackValue="" />
                                </TextBlock.Text></TextBlock>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Expander>
    <v:DocumentView x:Name="documentView"
                    Grid.Column="1"
                    Grid.Row="0"
                    DocumentID="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:BatchView}}, Path=ViewModel.SelectedItem.ID}"
                    IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:BatchView}}, Path=IsActive}" />
    <StackPanel Grid.Column="1"
                Grid.Row="1"
                Style="{StaticResource buttonStackStyle}">
        <Button Command="{Binding Path=PreviousCommand}"
                Style="{StaticResource previousButtonStyle}" />
        <Button Command="{Binding Path=NextCommand}"
                Style="{StaticResource nextButtonStyle}" />
    </StackPanel>
</Grid>

Кто-нибудь может подсказать, как я мог бы установить Высота ListBox в ActualHeight родительского Grid.Row?Или кто-нибудь может предложить лучшее решение?

Спасибо.

1 Ответ

1 голос
/ 10 ноября 2011

Короткая версия: удалить Grid.RowSpan из расширителя.

Длинная версия:

Фон: (очень широкими мазками)

Когда вы определяете высоту RowDefinition, могут произойти три вещи, в зависимости от того, какие единицы измерения вы используете:

  1. Пиксель - любой элемент UIElement, помещенный в эту строку, будет иметь определенную высоту строки, переданную методам Measure и Arrange элемента.
  2. Авто - сетка пройдет бесконечность как высоту для Measure, а затем element.DesiredSize.Height для Arrange.
  3. Звезда - сетка будет учитывать высоту всех строк с единицами пикселей и авто; вычислите высоту, оставшуюся от ее доступной высоты, и разделите ее на «общее количество звезд», которые были определены для всех рядов - это высота одной звезды; затем каждая высота строки назначается в зависимости от множителя для его определения звезды; эта высота передается методам Measure и Arrange.

Та же логика применяется к определениям столбцов только в отношении ширины, а не высоты.

Итак, определение «звезда» «останавливает» элемент, определение пикселя также «останавливает», но оно может находиться за пределами визуализированного представления, а автоматическое определение «позволяет» элементу иметь любой размер, какой он хочет.

Вся эта логика рекурсивна, поэтому вам нужно думать в двух направлениях (объяснение ниже).

В вашем случае

В одну сторону. ListBox находится в звездном ряду, поэтому он будет остановлен. Родительская сетка также останавливается (поскольку шаблон для расширителя использует DockPanel, который также является «панелью остановки»). Расширитель определен, чтобы начинаться в ряду звезд, но он охватывает автоматический ряд - это означает, что ему будет позволено расти в высоту 'до бесконечности. Упс ... время повернуть вспять.

Теперь обратное направление. Расширитель не останавливается, дочерняя сетка не останавливается (поскольку сетка предполагает, что она имеет бесконечную доступную высоту), поэтому список не останавливается, ScrollViewer в шаблоне списка не останавливается, поэтому он ViewportHeight является бесконечным, для VirtualizingStackPanel, который упорядочивает элементы (и является дочерним элементом средства просмотра прокрутки), это означает, что все элементы находятся в представлении == отображать все элементы.

Для окна WPF с шаблоном по умолчанию вы всегда можете предположить, что окно останавливает свой дочерний элемент. Поэтому, если удаление определения диапазона строк не решило проблему, продолжайте обход, пока не найдете другой элемент, который не останавливает его дочернюю высоту, и не измените его определения или не измените панель, чтобы остановить рост высоты до бесконечности (средства просмотра прокрутки печально известны создание этих поведений, особенно тех, которые скрыты в шаблонах).

...