ListBox以某种方式“窃取”此事件吗?
<ScrollViewer VerticalScrollBarVisibility="Auto" Style="{StaticResource myStyle}"> <ListBox> <ListBoxItem>Test 1</ListBoxItem> <ListBoxItem>Test 2</ListBoxItem> <ListBoxItem>Test 3</ListBoxItem> <ListBoxItem>Test 4</ListBoxItem> <ListBoxItem>Test 5</ListBoxItem> <ListBoxItem>Test 6</ListBoxItem> <ListBoxItem>Test 7</ListBoxItem> </ListBox> </ScrollViewer>
编辑:按照乔尔的要求,添加了我这样做的原因..
我这样做是因为我不喜欢ListBox的内部ScrollViewer对我的布局所做的事情.我有一个背景图片,最重要的是ListBox,如下所示:
alt text http://robbertdam.nl/share/1.png
现在,当滚动条出现时,会发生以下情况:
alt text http://robbertdam.nl/share/2.png
我为ScrollViewer创建了一个Style,它在ListBox项目的内容之上显示滚动条.在ListBox项的datatemplate中,我为滚动条保留了一些空间.
谢谢,
罗伯特大坝
解决方法
如果将ListBox放在ScrollViewer中,那么control template for ListBox内部仍然有自己的ScrollViewer.当鼠标光标位于ListBox上并滚动鼠标滚轮时,该事件会一直冒泡,直到它到达属于ListBox的ScrollViewer.那个人通过滚动处理它并将事件标记为已处理,因此将ListBox放入其中的ScrollViewer忽略该事件.
如果你使ListBox比外部ScrollViewer更高更窄,并给它足够的项目以便ListBox本身可以滚动项目,你会看到2个垂直滚动条:ListBox中有1个,外部有ListBox外有1个ScrollViewer中.当鼠标光标位于ListBox内部时,ListBox将使用其内部ScrollViewer滚动项目,其边框将保持不变.当鼠标光标位于ListBox外部并位于外部ScrollViewer内部时,ScrollViewer将滚动其内容 – ListBox – 您可以通过注意ListBox的Border更改位置来验证它.
如果你想让一个外部的ScrollViewer滚动整个ListBox控件(包括Border而不仅仅是项目),你需要重新设置ListBox的样式,使它没有内部的ScrollViewer,但是你还需要确保它根据其项目自动变大.
出于某些原因,我不推荐这种方法.如果ScrollViewer中有其他控件和ListBox,则可能有意义,但您的示例并未指出.此外,如果您要在ListBox中拥有大量项目,那么您将为每一个项目创建ListBoxItems,从而消除了由于默认的VirtualizingStackPanel而默认的,非重新设置样式的ListBox为您提供的任何优势.
请告诉我们您的实际要求.
编辑:好的,现在我有一个更好的主意,添加了这些图像.您得到的效果是,当有足够的项目滚动并且滚动条出现时,可用区域必须水平缩小一点,因为ScrollViewer的模板使用网格.这些似乎是你的选择,按顺序越来越好:
>将ListBox重新设置为没有ScrollViewer,并在ListBox外部使用重新设置样式的ScrollViewer.然后,您还必须强制ListBox也足够高,以显示相同样式中的每个项目,现在您已经失去了UI虚拟化.如果您要在列表中显示数百个项目,那么您绝对不想失去它.
>重新设置ListBox的样式,并将ControlTemplate设置为使用ScrollViewer,该ScrollViewer具有您为其创建的样式,将滚动条放在内容上而不是单独的列中.这个没问题(ListBox可以限制它的高度并使用VirtualizingStackPanel,但是正如你所说,它需要在你的DataTemplate中意识到这一点.
>重新设置ScrollViewer的样式,为垂直滚动条留出空间,即使它不可见.这是这个选项的样子:
默认情况下,ScrollViewer在Grid中使用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>
所以现在ScrollViewer的自定义Style中的ControlTemplate可能如下所示:
<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不必为滚动条的宽度进行补偿,因为无论滚动条是否可见,它都可以使用一致的区域.
您可能想要查看example ControlTemplate
for ScrollViewer
的其余部分,但这些示例不是默认样式.请注意,该示例将垂直滚动条放在左侧!另请注意底部有关ContentScrollPresenter的评论.