Виртуализация WPF ListBox завинчивает отображенные объекты

те, которые варьируются меньше, были бы первыми двумя для major.minor, после этого это может быть что-либо от сборки, пересмотра, выпуска, к любым пользовательским алгоритмам (как в некоторых продуктах MS)

9
задан Adel Hazzah 10 December 2009 в 06:46
поделиться

2 ответа

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

Предупреждение: Все усложняется, когда я объясню свои выводы.

Основная проблема возникает из-за того, что ширина элементов управления растягивается до ширины их контейнера. Когда виртуализация включена, ширина не изменится. В базовом ScrollViewer внутри ListBox свойство ViewportWidth соответствует ширине, которую вы видите. Когда другой элемент управления растягивается дальше (вы выбираете его), ViewportWidth остается прежним, но ExtentWidth показывает полную ширину. Привязка ширины всех элементов управления к ширине ExtentWidth должна работать ...

Но это не так. Я установил для FontSize значение 100 для более быстрого тестирования в моем случае. Когда выбран элемент, ExtentWidth = "4109.13 . Спускаясь по дереву к Border вашего ControlTemplate, я вижу ActualWidth =" 4107.13 ". Почему 2 пикселя разница? ListBoxItem содержит границу с заполнением 2 пикселя, в результате чего ContentPresenter становится немного меньше.

Я добавил следующий стиль с помощью отсюда , чтобы я мог напрямую получить доступ к ExtentWidth:

<Style x:Key="{x:Type ListBox}" TargetType="ListBox">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ListBox">
        <Border 
          Name="Border" 
          Background="White"
          BorderBrush="Black"
          BorderThickness="1"
          CornerRadius="2">
          <ScrollViewer 
            Name="scrollViewer"
            Margin="0"
            Focusable="false">
            <StackPanel IsItemsHost="True" />
          </ScrollViewer>
        </Border>
        <ControlTemplate.Triggers>
          <Trigger Property="IsEnabled" Value="false">
            <Setter TargetName="Border" Property="Background"
                    Value="White" />
            <Setter TargetName="Border" Property="BorderBrush"
                    Value="Black" />
          </Trigger>
          <Trigger Property="IsGrouping" Value="true">
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Обратите внимание, что для этой цели я добавил имя в ScrollViewer .

Затем, Я попытался привязать ширину вашей границы к ExtentWidth:

Width="{Binding ElementName=scrollViewer, Path=ExtentWidth}"

Однако из-за этого двухпиксельного отступа элементы управления будут изменять размер в бесконечном цикле, с добавлением 2 пикселей к ExtentWidth , который изменяет ширину границы, которая добавляет 2 пикселя к ExtentWidth и т. д., пока вы не удалите код и не обновите его.

Если вы добавили Converter, который вычитал 2 из ExtentWidth, я думаю, это могло бы Работа. Однако, если полоса прокрутки не существует (вы ничего не выбрали), ExtentWidth = "0" . Таким образом, привязка к MinWidth вместо Width может работать лучше, поэтому элементы отображаются правильно, когда полоса прокрутки не видна:

MinWidth="{Binding ElementName=scrollViewer, Path=ExtentWidth, Converter={StaticResource PaddingSubtractor}}"

Лучшее решение было бы, если бы вы могли напрямую привязать MinWidth самого ListBoxItem . Вы можете выполнить привязку напрямую к ExtentWidth, и никакого преобразователя не потребуется. Однако я понятия не имею, как получить доступ к этому элементу.

Edit: Для организации, вот клип, необходимый для этого. Делает все остальное ненужным:

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="MinWidth" Value="{Binding Path=ExtentWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}" />
</Style>
3
ответ дан 3 November 2019 в 07:13
поделиться

Благодаря великолепному анализу Уилла!

На основании предложения Уилла: « Лучшим решением было бы, если бы вы могли напрямую привязать MinWidth самого ListBoxItem ... Однако у меня есть не знаю, как получить доступ к этому элементу ", я смог реализовать это, используя чистый xaml, следующим образом:

<ListBox x:Name="_list" 
         Background="Gray" 
         Foreground="White"
         IsSynchronizedWithCurrentItem="True" 
         TextElement.FontSize="28"
         HorizontalContentAlignment="Stretch"
         ItemTemplate="{DynamicResource MyGroupItemTemplate}">

    <!-- Here is Will's suggestion, implemented in pure xaml. Seems to work.
         Next problem is if you drag the Slider to the right to increase the FontSize.
         This will make the horizontal scroll bar appear, as expected.
         Problem: the horizontal scroll bar never goes away if you drag the Slider to the left to reduce the FontSize.
    -->
    <ListBox.Resources>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="MinWidth" Value="{Binding Path=ExtentWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}}}" />
        </Style>
    </ListBox.Resources>

    <TextBlock Text="[1] This is item 1." />
    <TextBlock Text="[2] This is item 2." />
    <TextBlock Text="[3] This is item 3." />
    <TextBlock Text="[4] This is item 4." />
    <TextBlock Text="[5] This is item 5." />
    <TextBlock Text="[6] This is item 6." />
    <TextBlock Text="[7] This is item 7." />
    <TextBlock Text="[8] This is item 8." />
    <TextBlock Text="[9] This is item 9." />
    <TextBlock Text="[10] This is item 10." />
</ListBox>

Я почерпнул идею из замечательной книги Адама Натана », Windows Presentation Foundation Unleashed ".

Итак, похоже, это решает исходную проблему.

Новая проблема

Вы заметили, что в xaml есть элемент управления Slider, который позволяет вам увеличивать / уменьшать шрифт ListBox . Идея заключалась в том, чтобы позволить пользователю масштабировать содержимое ListBox вверх или вниз для облегчения видимости.

Если сначала перетащите ползунок вправо , чтобы увеличить размер шрифта, появится горизонтальная полоса прокрутки, как и ожидалось. Новая проблема заключается в том, что горизонтальная полоса прокрутки никогда не исчезает, если вы перетащите ползунок влево, чтобы уменьшить размер шрифта .

Есть идеи?

2
ответ дан 3 November 2019 в 07:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: