wpf 滚动查看器的子元素阻止使用鼠标滚轮滚动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14348517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:38:38  来源:igfitidea点击:

Child elements of scrollviewer preventing scrolling with mouse wheel?

wpfevent-handlinglistboxscrollviewermousewheel

提问by Tom

I'm having a problem getting mouse wheel scrolling to work in the following XAML, which I have simplified for clarity:

我在使鼠标滚轮滚动以在以下 XAML 中工作时遇到问题,为了清楚起见,我对其进行了简化:

<ScrollViewer
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
CanContentScroll="False"
>
    <Grid
    MouseDown="Editor_MouseDown"
    MouseUp="Editor_MouseUp"
    MouseMove="Editor_MouseMove"
    Focusable="False"
    >
        <Grid.Resources>
            <DataTemplate
            DataType="{x:Type local:DataFieldModel}"
            >
                <Grid
                Margin="0,2,2,2"
                >
                    <TextBox
                    Cursor="IBeam"
                    MouseDown="TextBox_MouseDown"
                    MouseUp="TextBox_MouseUp"
                    MouseMove="TextBox_MouseMove"
                    />
                </Grid>
            </DataTemplate>
        </Grid.Resources>
        <ListBox
        x:Name="DataFieldListBox"
        ItemsSource="{Binding GetDataFields}"
        SelectionMode="Extended"
        Background="Transparent"
        Focusable="False"
        >
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
                <Style
                TargetType="ListBoxItem"
                >
                    <Setter
                    Property="Canvas.Left"
                    Value="{Binding dfX}"
                    />
                    <Setter
                    Property="Canvas.Top"
                    Value="{Binding dfY}"
                    />
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
    </Grid>
</ScrollViewer>

Visually, the result is an area of some known size where DataFields read from a collection can be represented with TextBoxes which have arbitrary position, size, et cetera. In cases where the ListBox's styled "area" is too large to display all at once, horizontal and vertical scrolling is possible, but only with the scroll bars.

从视觉上看,结果是一个已知大小的区域,其中DataField从集合中读取的 s 可以用TextBox具有任意位置、大小等的 es表示。如果ListBox的样式“区域”太大而无法一次显示,则可以进行水平和垂直滚动,但只能使用滚动条。

For better ergonomics and sanity, mouse wheel scrolling should be possible, and normally ScrollViewerwould handle it automatically, but the ListBoxappears to be handing those events such that the parent ScrollViewernever sees them. So far I have only been able to get wheel scrolling working be setting IsHitTestVisible=Falsefor either the ListBoxor the parent Grid, but of course none of the child element's mouse events work after that.

为了更好的人体工程学和理智,鼠标滚轮滚动应该是可能的,并且通常ScrollViewer会自动处理它,但ListBox似乎正在处理这些事件,以便父母ScrollViewer永远不会看到它们。到目前为止,我只能IsHitTestVisible=False为 theListBox或 parent设置滚轮滚动Grid,但当然之后没有任何子元素的鼠标事件起作用。

What can I do to ensure the ScrollViewersees mouse wheel events while preserving others for child elements?

我该怎么做才能确保ScrollViewer看到鼠标滚轮事件,同时为子元素保留其他事件?

Edit: I just learned that ListBoxhas a built-in ScrollViewerwhich is probably stealing wheel events from the parent ScrollViewerand that specifying a control template can disable it. I'll update this question if that resolves the problem.

编辑:我刚刚了解到它ListBox有一个内置的ScrollViewer可能会从父级窃取轮子事件,ScrollViewer并且指定一个控件模板可以禁用它。如果解决了问题,我会更新这个问题。

采纳答案by Tom

Specifying a ControlTemplatefor the Listboxwhich doesn't include a ScrollViewersolves the problem. See this answerand these two MSDN pages for more information:

ControlTemplateListbox不包含 a 的指定 a可以ScrollViewer解决问题。有关更多信息,请参阅此答案和这两个 MSDN 页面:

ControlTemplate

控制模板

ListBox Styles and Templates

列表框样式和模板

回答by JoeB

You can also create a behavior and attach it to the parent control (in which the scroll events should bubble through).

您还可以创建一个行为并将其附加到父控件(滚动事件应该在其中冒泡)。

// Used on sub-controls of an expander to bubble the mouse wheel scroll event up 
public sealed class BubbleScrollEvent : Behavior<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
        base.OnDetaching();
    }

    void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        e.Handled = true;
        var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
        e2.RoutedEvent = UIElement.MouseWheelEvent;
        AssociatedObject.RaiseEvent(e2);
    }
}

<SomePanel>
            <i:Interaction.Behaviors>
                <viewsCommon:BubbleScrollEvent />
            </i:Interaction.Behaviors>
</SomePanel>

回答by kahr

Another way of implementing this, is by creating you own ScrollViewer like this:

实现这一点的另一种方法是像这样创建你自己的 ScrollViewer:

public class MyScrollViewer : ScrollViewer
{
    protected override void OnMouseWheel(MouseWheelEventArgs e)
    {
        var parentElement = Parent as UIElement;
        if (parentElement != null)
        {
            if ((e.Delta > 0 && VerticalOffset == 0) ||
                (e.Delta < 0 && VerticalOffset == ScrollableHeight))
            {
                e.Handled = true;

                var routedArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
                routedArgs.RoutedEvent = UIElement.MouseWheelEvent;
                parentElement.RaiseEvent(routedArgs);
            }
        }

        base.OnMouseWheel(e);
    }
}

回答by sean.net

I know it's a little late but I have another solution that worked for me. I switched out my stackpanel/listbox for an itemscontrol/grid. Not sure why the scroll events work properly but they do in my case.

我知道现在有点晚了,但我有另一个对我有用的解决方案。我为 itemscontrol/grid 切换了我的 stackpanel/listbox。不知道为什么滚动事件可以正常工作,但在我的情况下可以。

<ScrollViewer VerticalScrollBarVisibility="Auto" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
                <StackPanel Orientation="Vertical">
                    <ListBox ItemsSource="{Binding DrillingConfigs}" Margin="0,5,0,0">
                        <ListBox.ItemTemplate>
                            <DataTemplate>

became

变成了

<ScrollViewer VerticalScrollBarVisibility="Auto" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ItemsControl ItemsSource="{Binding DrillingConfigs}" Margin="0,5,0,0" Grid.Row="0">
            <ItemsControl.ItemTemplate>
                <DataTemplate>