将ListBox放在ScrollViewer中:鼠标滚轮不起作用

时间:2009-08-18 13:33:49

标签: c# wpf xaml listbox scrollviewer

ListBox放入ScrollViewer时,我的鼠标滚轮无效。

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>

编辑:按照Joel的要求,添加了我这样做的原因.. 我这样做是因为我不喜欢ListBox的内部ScrollViewer对我的布局所做的事情。我有一张背景图片,最重要的是ListBox,如下所示:

alt text http://robbertdam.nl/share/1.png

现在当滚动条出现时,会发生以下情况:

alt text http://robbertdam.nl/share/2.png

我为ScrollViewer创建了一个样式,用于显示ListBox项内容的顶部上的滚动条。在ListBox项的datatemplate中,我为滚动条保留了一些空间。

谢谢, 罗伯特大坝

4 个答案:

答案 0 :(得分:15)

首先,我认为您需要详细说明您的限制是什么以及您想要实现的目标。没有它,我只能解释为什么你所做的不起作用。有些人甚至可能对如何获得你想要的结果有更好的了解。

如果您将ListBox放在ScrollViewer内,那么ListBox的{​​{3}}内部仍然有自己的ScrollViewer。当鼠标光标位于ListBox上方并滚动鼠标滚轮时,该事件会一直冒泡,直到它到达ScrollViewer ListBox的一部分。那个人通过滚动处理它并将事件标记为已处理,因此ScrollViewer放入ListBox忽略事件。

如果你使ListBox比外ScrollViewer更高更窄,并给它足够的项目,以便ListBox本身可以滚动项目,你会看到2垂直滚动条形:ListBox中有1条,外部ListBox位于ScrollViewer外1条。当鼠标光标位于ListBox内时,ListBox将使用其内部ScrollViewer滚动项目,其Border将保留在原位。当鼠标光标位于ListBox之外且位于外部ScrollViewer之内时,ScrollViewer将滚动其内容 - ListBox - 您可以通过注意到它来验证ListBox的{​​{1}}改变了位置。

如果您希望外部Border滚动整个ScrollViewer控件(包括ListBox而不仅仅是项目),则需要重新设置{{1所以它没有内部Border,但你还需要确保它根据其项目自动变大。

出于某些原因,我不推荐这种方法。如果ListBox内有其他控件和ScrollViewer,则可能有意义,但您的示例并未表明这一点。此外,如果您要在ScrollViewer中添加大量项目,则会为每个项目创建ListBox个,从而消除了默认的非重新设置{ {1}}由于默认ListBox而为您提供。

请告诉我们您的实际要求。


编辑:好的,现在我有了更好的想法,添加了这些图片。您获得的效果是,当有足够的项目滚动并且滚动条出现时,可用区域必须水平缩小一点,因为ListBoxItem的模板使用ListBox。这些似乎是你的选择,按照从小到好的顺序:

  1. VirtualizingStackPanel重新设置为没有ScrollViewer,并在Grid之外使用重新设置的ListBox。然后,您还必须强制ScrollViewer也足够高,以显示同一ScrollViewer中的每个项目,现在您已经失去了UI虚拟化。如果您要在列表中显示数百个项目,那么肯定不想丢失它。
  2. 重新设置ListBox样式,并将ListBox设置为使用您已为其创建的样式的Style,将滚动条放在内容上而不是单独的列中。这一个没问题(ListBox限制其高度并使用ControlTemplate,yay),但正如您所说,它需要在ScrollViewer中意识到这一点。
  3. 重新设置ListBox样式,为垂直滚动条留出空间,即使它不可见。以下是此选项的含义:
  4. 默认情况下,VirtualizingStackPanel使用与DataTemplate等效的2列:

    ScrollViewer

    因此,当ScrollViewer后滚动条不可见时,滚动条列的Grid为0。要为滚动条留出空间,即使它已被隐藏,我们也会将该列的<Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> 绑定到垂直滚动条的Width

    Width="Auto"

    现在,Width的自定义Width中的<Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" /> </Grid.ColumnDefinitions> 可能如下所示:

    ControlTemplate

    您甚至可以将内容列设置为固定大小和滚动条列Style,如果图像未拉伸,则可能会在长时间内更好地工作。现在ScrollViewer不必为滚动条的宽度进行补偿,因为无论滚动条是否可见,它都可以使用一致的区域。

    您可能希望查看control template的其余部分,但这些示例不是默认样式。 请注意,该示例将垂直滚动条放在左侧!另请注意底部有关<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>

    的评论

答案 1 :(得分:5)

我正在处理同样的问题。我设置了 ListBox.ItemsPanel 属性,没有任何 ScrollViewer

 <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
     <ListBox>
          <ListBox.Template>
             <ControlTemplate TargetType="ItemsControl">
                 <Border>
                     <ItemsPresenter />
                 </Border>
             </ControlTemplate>
          </ListBox.Template>
          <ListBox.ItemsPanel>
              <ItemsPanelTemplate>
                  <VirtualizingStackPanel />
              </ItemsPanelTemplate>
          </ListBox.ItemsPanel>
    <\ListBox>
<\ScrollViewer>

希望这有帮助。

答案 2 :(得分:0)

请参阅此链接以获取其他答案:Scroll in ScrollViewer when mouse over ListBox

您好,我认为您可以处理整个ListBox的PreviewMouseWheel事件。只要您不处理每个项目的

,这也会影响单个项目
PreviewMouseWheel and mark the event as handled:
    private void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (e.Delta < 0)
        {
            scrollViewer1.LineDown();
        }
        else
        {
            scrollViewer1.LineUp();
        }
    }

答案 3 :(得分:0)

如果您只想使鼠标滚动而无需为 ScrollViewer 设置样式:

  • 移除外部的 ScrollViewer。
  • 使用 ScrollViewer 的附加属性,它位于 ListBox 内。

请参阅此示例的前两行:

<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto">
  <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>