scrollviewer的子元素阻止滚动鼠标滚轮?

Tom*_*Tom 30 wpf listbox event-handling mousewheel scrollviewer

我在使用鼠标滚轮在以下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>
Run Code Online (Sandbox Code Playgroud)

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

为了更好的人体工程学和理智,鼠标滚轮应该是可能的,并且通常ScrollViewer会自动处理它,但ListBox似乎是处理这些事件,使父母ScrollViewer永远不会看到它们.到目前为止,我只能够得到滚轮滚动的工作是设定IsHitTestVisible=False为无论是ListBox或家长Grid,当然没有一个子元素的鼠标事件后,这项工作.

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

编辑:我刚学会ListBox了内置的,ScrollViewer可能是从父级窃取轮子事件,ScrollViewer而指定控件模板可能会禁用它.如果能解决问题,我会更新这个问题.

Joe*_*oeB 54

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

// 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>
Run Code Online (Sandbox Code Playgroud)

  • 只是给其他试图使用此解决方案的人留言.您需要安装Expression Blend SDK才能访问`System.Windows.Interactivity`.NuGet命令`Install-Package Expression.Blend.Sdk`将为您安装它. (6认同)
  • 有用 !!!非常感谢(不要忘记添加命名空间xmlns:i ="clr-namespace:System.Windows.Interactivity; assembly = System.Windows.Interactivity") (4认同)
  • @BradleyUffner FYI,在没有Expression Blend SDK的VS2013 Ultimate上为我工作.有趣的是,ReSharper添加了命名空间`xmlns:i ="http://schemas.microsoft.com/expression/2010/interactivity",所以不确定它是否只是包含在内. (3认同)

Tom*_*Tom 12

指定ControlTemplateListbox不包括ScrollViewer解决问题.有关详细信息,请参阅此答案和这两个MSDN页面:

控件模板

列表框样式和模板


小智 5

实现这一点的另一种方法是像这样创建你自己的 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);
    }
}
Run Code Online (Sandbox Code Playgroud)