将 ListBox 放入 ScrollViewer:鼠标滚轮不起作用 [英] Putting ListBox in ScrollViewer: mouse wheel does not work

查看:18
本文介绍了将 ListBox 放入 ScrollViewer:鼠标滚轮不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ListBox 放入 ScrollViewer 时,我的鼠标滚轮不起作用.

My mouse wheel does not work when putting a ListBox in a ScrollViewer.

ListBox 是否以某种方式窃取"了这个事件?

Does the ListBox somehow "steal" this event?

<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,如下所示:

as requested by Joel, added the reason why I did this.. I did this because I don't like what the ListBox's internal ScrollViewer does with my layout. I have a background image, and on top of that a ListBox as shown here:

替代文字 http://robbertdam.nl/share/1.png

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

Now when the scrollbar appears, the following happens:

替代文字 http://robbertdam.nl/share/2.png

我为 ScrollViewer 创建了一个样式,它在 ListBox 项的内容的顶部显示滚动条.在 ListBox 项目的数据模板中,我为滚动条保留了一些空间.

I've created a Style for a ScrollViewer that shows the scroll bar on top of the ListBox item's content. In the ListBox item's datatemplate I've reserved some space for the scrollbar to appear.

谢谢,罗伯特水坝

推荐答案

首先,我认为您需要详细说明您的限制是什么以及您想要实现的目标.没有那个,我只能解释为什么你正在做的事情不起作用.有人甚至可能对如何获得您所追求的结果有更好的想法.

Firstly, I think you need to elaborate on what your limitations are and what you're trying to achieve. Without that, I can only explain why what you're doing isn't working. Somebody may even have a better idea about how to get the result you're after.

如果您将 ListBox 放在 ScrollViewer 中,那么 控件模板 内部仍然有自己的 ScrollViewer.当鼠标光标在 ListBox 上并滚动鼠标滚轮时,该事件会冒泡,直到它到达 ScrollViewer,它是 ListBox 的一部分.那一个通过滚动来处理它并将事件标记为已处理,因此您将 ListBox 放在其中的 ScrollViewer 会忽略该事件.

If you put ListBox inside a ScrollViewer, then the control template for ListBox still has its own ScrollViewer inside. When the mouse cursor is over the ListBox and you scroll the mousewheel, that event bubbles up until it reaches the ScrollViewer that's part of ListBox. That one handles it by scrolling and marks the event as handled, so then the ScrollViewer you put the ListBox inside of ignores the event.

如果你让 ListBox 比外面的 ScrollViewer 更高和更窄,并给它足够的项目,以便 ListBox 本身可以滚动项目,您将看到 2 个垂直滚动条:1 个位于 ListBox 中,1 个位于 ListBox 外部,用于您的外部 ScrollViewer.当鼠标光标在 ListBox 内时,ListBox 将使用其内部 ScrollViewer 及其 Border 滚动项目> 将留在原地.当鼠标光标在 ListBox 之外并且在外部 ScrollViewer 内时,该 ScrollViewer 将滚动其内容 -- ListBox -- 您可以通过注意 ListBoxBorder 更改位置来验证.

If you make the ListBox taller and narrower than the outer ScrollViewer, and give it enough items so that the ListBox itself can scroll the items, you'll see 2 vertical scroll bars: 1 in the ListBox, and 1 outside the ListBox for your outer ScrollViewer. When the mouse cursor is inside the ListBox, the ListBox will scroll the items with its internal ScrollViewer, and its Border will stay in place. When the mouse cursor is outside the ListBox and inside the outer ScrollViewer, that ScrollViewer will scroll its contents -- the ListBox -- which you can verify by noting that the ListBox's Border changes position.

如果您希望外部 ScrollViewer 滚动整个 ListBox 控件(包括 Border 而不仅仅是项目),您将需要重新设置 ListBox 的样式,使其没有内部 ScrollViewer,但您还需要确保它根据项目自动变大.

If you want an outer ScrollViewer to scroll the entire ListBox control (including the Border and not just the items), you'll need to re-style the ListBox so that it does not have an internal ScrollViewer, but you'll also need to make sure it automatically gets bigger according to its items.

出于几个原因,我不推荐这种方法.如果 ScrollViewerListBox 内还有其他控件可能有意义,但您的示例并未表明这一点.此外,如果您要在 ListBox 中有很多项目,您将为每个项目创建 ListBoxItem,从而消除默认设置的任何优势,由于默认的 VirtualizingStackPanel,非重新样式的 ListBox 为您提供.

I don't recommend this approach for a couple reasons. It might make sense if there are other controls inside the ScrollViewer along with the ListBox, but your sample does not indicate that. Also, if you're going to have a lot of items in the ListBox, you'll be creating ListBoxItems for every single one, eliminating any advantage that the default, non-re-styled ListBox gives you due to the default VirtualizingStackPanel.

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

Please let us know what your actual requirements are.

好的,现在我有了更好的主意,添加了这些图像.你得到的效果是当有足够的项目滚动并且出现滚动条时,可用区域必须水平缩小一点,因为 ScrollViewer 的模板使用 Grid.这些似乎是您的选择,按从小到大的顺序排列:

Ok, now I have a little better idea, with the addition of those images. The effect you're getting is that when there are enough items to scroll and the scrollbar appears, the available area has to shrink a bit horizontally because the ScrollViewer's template uses a Grid. These seem to be your options, in order of lesser-to-better:

  1. 重新设置 ListBox 的样式,使其没有 ScrollViewer 并在 ListBoxScrollViewer>.然后,您还必须强制 ListBox 也足够高以显示同一 Style 中的每个项目,现在您已经失去了 UI 虚拟化.如果您要在列表中显示数百个项目,那么您肯定不想丢失它.
  2. 重新设置 ListBox 的样式并将 ControlTemplate 设置为使用 ScrollViewer 并使用您已经为其创建的样式来放置滚动条内容而不是在单独的列中.这个没问题(ListBox 可以限制其高度并使用 VirtualizingStackPanel,是的),但正如您所说,它需要在您的 DataTemplate.
  3. 重新设置 ScrollViewer 的样式,以便为垂直滚动条留出空间,即使它不可见.此选项如下所示:
  1. Re-style the ListBox to not have a ScrollViewer and use your re-styled ScrollViewer outside the ListBox. You'd then also have to force the ListBox to also be tall enough to show every item in that same Style, and now you've lost UI virtualization. If you're going to be showing hundreds of items in the list, you definitely don't want to lose that.
  2. Re-style the ListBox and set the ControlTemplate to use a ScrollViewer with the style you already created for it that puts the scrollbar over the content rather than in a separate column. This one's ok (ListBox gets to limit its height and use a VirtualizingStackPanel, yay), but as you said, it necessitates awareness of that in your DataTemplate.
  3. Re-style the ScrollViewer to leave space for vertical scrollbar even when it is not visible. Here's what this option looks like:

默认情况下,ScrollViewerGrid 中使用 2 列,相当于:

By default, ScrollViewer uses 2 columns in a Grid equivalent to this:

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

因此,当滚动条自Width="Auto" 以来不可见时,滚动条列的Width 为0.为了在滚动条隐藏时也为滚动条留出空间,我们将该列的 Width 绑定到垂直滚动条的 Width :

So the Width of the scrollbar's column is 0 when the scrollbar is not visible since Width="Auto". To leave space for the scrollbar even when it is hidden, we bind the Width of that column to the Width of the vertical scroll bar:

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

所以现在 ScrollViewer 的自定义 Style 中的 ControlTemplate 可能如下所示:

So now the ControlTemplate in the custom Style for ScrollViewer might look like this:

<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 不必补偿滚动条的宽度,因为它获得了一致的区域来使用滚动条是否可见.

You could even make the content column a fixed size and the scrollbar column Width="*", which might work better in the long run if your image is not stretched. Now the DataTemplate does not have to compenstate for the width of a scrollbar, as it gets a consistent area to use whether the scrollbar is visible or not.

您可能需要查看 示例 的其余部分ScrollViewer 的 ControlTemplate,但这些示例不是默认样式.请注意,该示例将垂直滚动条放在左侧!还要注意底部关于 ContentScrollPresenter 的注释.

You'll probably want to check out the rest of the example ControlTemplate for ScrollViewer, but those examples are not the default styles. Note that the example puts the vertical scrollbar on the left! Also note the comment at the bottom about ContentScrollPresenter.

这篇关于将 ListBox 放入 ScrollViewer:鼠标滚轮不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆