Помещение ListBox в ScrollViewer: колесо мыши не работает

Это не точно верно, что "утверждают сбои только в режиме отладки".

В Разработка объектно-ориентированного программного обеспечения, 2-й Выпуск Bertrand Meyer, автор оставляет дверь открытой для проверки предварительных условий в режиме выпуска. В этом случае, что происходит, когда утверждение перестало работать, то, что... исключение нарушения утверждения повышено! В этом случае нет никакого восстановления после ситуации: что-то полезное могло быть сделано, хотя, и оно должно автоматически генерировать сообщение об ошибке и, в некоторых случаях, для перезапуска приложения.

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

необходимо ли всегда уезжать, проверки предварительного условия включили? Это зависит.Ваш решать. Нет никакого универсального ответа. При создании программного обеспечения для банка могло бы быть лучше прервать выполнение аварийным сообщением, чем передать 1 000 000$ вместо 1 000$. Но что, если Вы программируете игру? Возможно, Вам нужна вся скорость, которую можно получить, и если кто-то понимает 1 000 мыслей вместо 10 из-за ошибки, которую предварительные условия не поймали (потому что им не включают), жесткая удача.

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

подводя итоги, Вы можете иметь утверждения и все еще получить исключения автоматически при отъезде их, включил - по крайней мере, в Eiffel. Я думаю, чтобы сделать то же в C++, необходимо ввести его сами.

См. также: , Когда утверждения должны остаться в производственном коде?

8
задан Dave Clemmer 8 August 2011 в 21:14
поделиться

1 ответ

Во-первых, я думаю, вам нужно уточнить, в чем заключаются ваши ограничения и чего вы пытаетесь достичь. Без этого я могу только объяснить, почему то, что вы делаете, не работает. Кто-то может даже лучше понять, как получить желаемый результат.

Если вы поместите ListBox в ScrollViewer , то шаблон элемента управления ] для ListBox по-прежнему имеет собственный ScrollViewer внутри. Когда курсор мыши находится над ListBox и вы прокручиваете колесо мыши, это событие всплывает вверх, пока не достигнет ScrollViewer , который является частью ListBox . Тот обрабатывает это путем прокрутки и отмечает событие как обработанное, поэтому ScrollViewer , который вы помещаете ListBox внутрь, игнорирует событие.

Если вы сделаете ListBox выше и уже, чем внешний ScrollViewer , и дайте ему достаточно элементов, чтобы сам ListBox мог прокручивать элементы, вы увидите 2 вертикальные полосы прокрутки: 1 в ListBox и 1 за пределами ListBox для внешнего ScrollViewer . Когда курсор мыши находится внутри ListBox , ListBox будет прокручивать элементы с помощью своего внутреннего ScrollViewer , а его Border останется в место. Когда курсор мыши находится за пределами ListBox и внутри внешнего ScrollViewer , что ScrollViewer будет прокручивать свое содержимое - ListBox - в чем вы можете убедиться, заметив, что Border ListBox меняет положение .

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

Я не знаю. Я не рекомендую этот подход по нескольким причинам. Это может иметь смысл, если внутри ScrollViewer есть другие элементы управления вместе с ListBox , но в вашем примере это не указано. Кроме того, если вы Если в ListBox будет много элементов, вы создадите ListBoxItem для каждого из них, исключив любое преимущество, которое имеет значение по умолчанию, без повторного стиля ListBox дает вам из-за значения по умолчанию VirtualizingStackPanel .

Пожалуйста, дайте нам знать, каковы ваши фактические требования.


Изменить: Хорошо, теперь у меня есть немного лучшее представление, с добавлением этих изображений. Эффект, который вы получаете, заключается в том, что, когда имеется достаточно элементов для прокрутки и появляется полоса прокрутки, доступная область должна немного сжиматься по горизонтали, потому что шаблон ScrollViewer использует сетку . Похоже, это ваши варианты в порядке от меньшего к лучшему:

  1. Измените стиль ListBox , чтобы не было ScrollViewer , и используйте измененный стиль ScrollViewer вне ListBox . Затем вам также придется заставить ListBox быть достаточно высоким, чтобы отображать каждый элемент в том же стиле , и теперь вы потеряли виртуализацию пользовательского интерфейса. Если вы собираетесь показывать сотни элементов в списке, вы определенно не хотите их потерять.
  2. Измените стиль ListBox и установите ControlTemplate , чтобы использовать ScrollViewer с уже созданным для него стилем, который помещает полосу прокрутки поверх содержимого, а не в отдельный столбец. Вот этот' s ok ( ListBox может ограничить свою высоту и использовать VirtualizingStackPanel , ура), но, как вы сказали, необходимо знать об этом в вашем DataTemplate .
  3. Измените стиль ScrollViewer , чтобы оставить место для вертикальной полосы прокрутки, даже если она не видна. Вот как выглядит этот параметр:

По умолчанию ScrollViewer использует 2 столбца в сетке , эквивалентных этому:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

Итак, Ширина столбец полосы прокрутки равен 0, если полоса прокрутки не отображается, поскольку Width = "Auto" . Чтобы оставить место для полосы прокрутки, даже если она скрыта, мы привязываем Ширина этого столбца к Ширина вертикальной полосы прокрутки:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition
        Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" />
</Grid.ColumnDefinitions>

Теперь ControlTemplate в пользовательском стиле для ScrollViewer может выглядеть следующим образом:

<ControlTemplate
    TargetType="{x:Type ScrollViewer}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition
                Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition
                Height="Auto" />
        </Grid.RowDefinitions>

        <ScrollContentPresenter />

        <ScrollBar
            Grid.Column="1"
            Name="PART_VerticalScrollBar"
            Value="{TemplateBinding VerticalOffset}"
            Maximum="{TemplateBinding ScrollableHeight}"
            ViewportSize="{TemplateBinding ViewportHeight}"
            Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
        <ScrollBar
            Name="PART_HorizontalScrollBar"
            Orientation="Horizontal"
            Grid.Row="1"
            Value="{TemplateBinding HorizontalOffset}"
            Maximum="{TemplateBinding ScrollableWidth}"
            ViewportSize="{TemplateBinding ViewportWidth}"
            Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />

    </Grid>
</ControlTemplate>

Вы даже можете сделать столбец содержимого фиксированного размера и столбец полосы прокрутки Width = "*" , который может работать лучше в долгосрочной перспективе, если ваше изображение не растягивается. Теперь DataTemplate не должен компенсировать ширину полосы прокрутки, поскольку он получает согласованную область, которую можно использовать независимо от того, видна полоса прокрутки или нет.

Вы, вероятно, захотите проверить остальное. из примера ControlTemplate для ScrollViewer , но эти примеры не являются стилями по умолчанию. Обратите внимание, что в примере вертикальная полоса прокрутки помещается слева! Также обратите внимание на комментарий внизу о ContentScrollPresenter .

15
ответ дан 5 December 2019 в 07:36
поделиться
Другие вопросы по тегам:

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