【问题标题】:Child elements of scrollviewer preventing scrolling with mouse wheel?scrollviewer 的子元素阻止使用鼠标滚轮滚动?
【发布时间】:2012-12-30 04:30:45
【问题描述】:

我在让鼠标滚轮滚动以在以下 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>

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

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

我可以做些什么来确保ScrollViewer 看到鼠标滚轮事件,同时为子元素保留其他事件?

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

【问题讨论】:

    标签: wpf event-handling listbox scrollviewer mousewheel


    【解决方案1】:

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

    // 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>
    

    【讨论】:

    • 有效!!!非常感谢(不要忘记添加命名空间 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity")
    • 只是对尝试使用此解决方案的其他人的说明。您需要安装 Expression Blend SDK 才能访问System.Windows.Interactivity。 NuGet 命令Install-Package Expression.Blend.Sdk 将为您安装它。
    • @JoeB 这是迄今为止更好的答案。轻松使用主题和其他样式/模板!
    • @BradleyUffner 仅供参考,在没有 Expression Blend SDK 的情况下为我在 VS2013 Ultimate 上工作。有趣的是,ReSharper 添加了命名空间 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity",所以不确定它现在是否刚刚包含在内。
    • +1 它有效,但我不明白它为什么有效 :( 在我所有的 WPF 经验中,设置 e.Handled = true 就足够了,但在这种情况下我必须再次提出这个事件!?无论如何,感谢您的解决方法!
    【解决方案2】:

    为不包含ScrollViewerListbox 指定ControlTemplate 可以解决问题。有关详细信息,请参阅 this answer 和这两个 MSDN 页面:

    ControlTemplate

    ListBox Styles and Templates

    【讨论】:

    • 这也适用于TreeView而不是ListBox。谢谢!
    【解决方案3】:

    实现这一点的另一种方法是创建自己的 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);
        }
    }
    

    【讨论】:

      【解决方案4】:

      我知道这有点晚了,但我有另一个对我有用的解决方案。我将我的堆栈面板/列表框切换为项目控件/网格。不知道为什么滚动事件可以正常工作,但在我的情况下它们可以正常工作。

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

      成为

      <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>
      

      【讨论】:

      • 这是因为 是更“愚蠢”的控件(实际上,它是 ListBox 的祖先)并且它根本不支持滚动。所以你得到了一个可能比以前版本(基于ListBox)慢的解决方案。
      猜你喜欢
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多