2013-01-15 107 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); 
    } 
}