2013-01-15 15 views
25

Sto avendo un problema ottenere rotella di scorrimento del mouse per lavorare nella seguente XAML, che ho semplificato per chiarezza:Elementi figlio di scrollviewer che impediscono lo scorrimento con la rotellina del mouse?

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

Visivamente, il risultato è una superficie di circa dimensioni note dove DataField s in lettura da una la collezione può essere rappresentata con TextBox es che hanno posizione, dimensione e così via arbitrarie. Nei casi in cui l'area "stile" di ListBox è troppo grande per essere visualizzata tutte contemporaneamente, è possibile eseguire lo scorrimento orizzontale e verticale, ma solo con le barre di scorrimento.

Per una migliore ergonomia e la sanità mentale, mouse rotella di scorrimento dovrebbe essere possibile, e normalmente ScrollViewer sarebbe gestire automaticamente, ma il ListBox sembra essere consegnare quegli eventi in modo tale che il genitore ScrollViewer non li vede. Finora sono stato in grado di ottenere lo scroll wheeling lavorando impostando IsHitTestVisible=False per il ListBox o il genitore Grid, ma ovviamente nessuno degli eventi del mouse dell'elemento figlio funziona dopo.

Cosa posso fare per garantire che lo ScrollViewer visualizzi gli eventi della rotellina del mouse conservando gli altri per gli elementi figlio?

Edit: ho appena saputo che ListBox ha un built-in ScrollViewer che probabilmente è rubando eventi ruota dal genitore ScrollViewer e che specifica un modello di controllo può disattivarlo. Aggiornerò questa domanda se questo risolve il problema.

risposta

43

È anche possibile creare un comportamento e allegarlo al controllo padre (in cui gli eventi di scorrimento dovrebbe bolla attraverso).

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

Funziona !!! Grazie mille (non dimenticare di aggiungere lo spazio dei nomi xmlns: i = "clr-namespace: System.Windows.Interactivity; assembly = System.Windows.Interactivity") –

+4

Solo una nota per chiunque altro stia tentando di utilizzare questa soluzione. È necessario installare Expression Blend SDK per accedere a "System.Windows.Interactivity". Il comando NuGet 'Install-Package Expression.Blend.Sdk' lo installerà per te. –

+1

@JoeB Questa è la risposta migliore di gran lunga. Funziona facilmente con temi e altri stili/modelli! – Darkhydro

2

So che è un po 'tardi ma ho un'altra soluzione che ha funzionato per me. Ho spento il mio stackpanel/listbox per un controllo/griglia di elementi. Non sono sicuro del motivo per cui gli eventi di scorrimento funzionano correttamente, ma lo fanno nel mio caso.

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

divenne

<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

Questo perché è un controllo più "stupido" (in realtà, è l'antenato di ListBox) e non ha alcun supporto per lo scrolling, quindi hai una soluzione che _potenzialmente_ è più lento della versione precedente (basata su ListBox). –

2

Un altro modo di attuazione del presente, è la creazione Possiedi uno ScrollViewer in questo modo:

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); 
    } 
} 
Problemi correlati