2013-01-15 79 views
25

我有越来越鼠标滚轮滚动在以下XAML,我已经为了清楚而简化工作的问题:scrollviewer的子元素阻止用鼠标滚轮滚动?

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

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

为了更好的人机工程学和理智,鼠标滚轮滚动应该是可能的,通常ScrollViewer会自动处理它,但ListBox似乎交给这些事件使得母ScrollViewer永远看不到它们。到目前为止,我只能使轮盘滚动工作设置IsHitTestVisible=FalseListBox或父Grid,但当然没有子元素的鼠标事件后工作。

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

编辑:我刚才得知ListBox有一个内置的ScrollViewer这可能是从父母ScrollViewer偷轮子事件,并指定一个控制模板可以禁用它。如果能解决问题,我会更新这个问题。

回答

43

您还可以创建一个行为,并将其连接到父控件(其中滚动事件应该通过泡)。

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

它的工作原理!非常感谢(不要忘记添加命名空间xmlns:i =“clr-namespace:System.Windows.Interactivity; assembly = System.Windows.Interactivity”) –

+4

只是给所有尝试使用此解决方案的人的一个提示。您将需要安装Expression Blend SDK才能访问'System.Windows.Interactivity'。 NuGet命令“Install-Package Expression.Blend.Sdk”将为您安装。 –

+1

@JoeB这是目前较好的答案。轻松与主题和其他样式/模板一起工作! – Darkhydro

2

我知道这有点晚,但我有另一种解决方案,为我工作。我把我的stackpanel/listbox换成了itemcontrol/grid。不知道为什么滚动事件正常工作,但他们在我的情况下。

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

这是因为更加“哑”控制(实际上,它是ListBox的祖先),它根本不支持滚动,所以你得到了一个解决方案_potentially_比以前的版本(基于ListBox的)慢。 –

2

实现这个的另一种方式,就是通过创建你自己的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); 
    } 
}