Это не точно верно, что "утверждают сбои только в режиме отладки".
В Разработка объектно-ориентированного программного обеспечения, 2-й Выпуск Bertrand Meyer, автор оставляет дверь открытой для проверки предварительных условий в режиме выпуска. В этом случае, что происходит, когда утверждение перестало работать, то, что... исключение нарушения утверждения повышено! В этом случае нет никакого восстановления после ситуации: что-то полезное могло быть сделано, хотя, и оно должно автоматически генерировать сообщение об ошибке и, в некоторых случаях, для перезапуска приложения.
мотивация позади этого - то, что предварительные условия являются обычно более дешевыми для тестирования, чем инварианты и постусловия, и что в некоторых случаях правильность и "безопасность" в сборке конечных версий более важны, чем скорость. т.е. Поскольку много скоростей приложений не являются проблемой, но устойчивость (способность программы вести себя безопасным способом, когда его поведение не корректно, т.е. когда условия контракта нарушены).
необходимо ли всегда уезжать, проверки предварительного условия включили? Это зависит.Ваш решать. Нет никакого универсального ответа. При создании программного обеспечения для банка могло бы быть лучше прервать выполнение аварийным сообщением, чем передать 1 000 000$ вместо 1 000$. Но что, если Вы программируете игру? Возможно, Вам нужна вся скорость, которую можно получить, и если кто-то понимает 1 000 мыслей вместо 10 из-за ошибки, которую предварительные условия не поймали (потому что им не включают), жесткая удача.
В обоих случаях необходимо было идеально поймать ту ошибку во время тестирования, и необходимо сделать значительную часть тестирования с включенными утверждениями. Что обсуждается, вот то, что является лучшей политикой для тех редких случаев, в которых предварительные условия перестали работать в производственном коде в сценарии, который не был обнаружен ранее из-за неполного тестирования.
подводя итоги, Вы можете иметь утверждения и все еще получить исключения автоматически при отъезде их, включил - по крайней мере, в Eiffel. Я думаю, чтобы сделать то же в C++, необходимо ввести его сами.
См. также: , Когда утверждения должны остаться в производственном коде?
Во-первых, я думаю, вам нужно уточнить, в чем заключаются ваши ограничения и чего вы пытаетесь достичь. Без этого я могу только объяснить, почему то, что вы делаете, не работает. Кто-то может даже лучше понять, как получить желаемый результат.
Если вы поместите 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
использует сетку
. Похоже, это ваши варианты в порядке от меньшего к лучшему:
ListBox
, чтобы не было ScrollViewer
, и используйте измененный стиль ScrollViewer
вне ListBox
. Затем вам также придется заставить ListBox
быть достаточно высоким, чтобы отображать каждый элемент в том же стиле
, и теперь вы потеряли виртуализацию пользовательского интерфейса. Если вы собираетесь показывать сотни элементов в списке, вы определенно не хотите их потерять. ListBox
и установите ControlTemplate
, чтобы использовать ScrollViewer
с уже созданным для него стилем, который помещает полосу прокрутки поверх содержимого, а не в отдельный столбец. Вот этот' s ok ( ListBox
может ограничить свою высоту и использовать VirtualizingStackPanel
, ура), но, как вы сказали, необходимо знать об этом в вашем DataTemplate
. 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
.