Éléments enfants de scrollviewer empêchant le défilement avec la roue de la souris?

j'ai un problème pour faire fonctionner le défilement de la souris dans le XAML suivant, que j'ai simplifié pour plus de clarté:

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

Visuellement, le résultat est un espace de taille connue où DataField S lu à partir d'une collection peut être représenté avec TextBox qui ont une position, une taille, etc. arbitraire. Dans les cas où l' est trop grande pour être affichée en même temps, le défilement horizontal et vertical est possible, mais seulement avec le défilement bars.

pour une meilleure ergonomie et santé, le défilement de la souris devrait être possible, et normalement ScrollViewer manipuler automatiquement, mais l' ListBox semble transmettre ces événements de telle sorte que le parent ScrollViewer ne les voit jamais. Pour l'instant j'ai seulement été en mesure d'obtenir de la roue de défilement de travail à définir IsHitTestVisible=False pour le ListBox ou le parent Grid, mais bien sûr aucun des évènements souris de l'élément enfant ne fonctionne après cela.

Que puis-je faire pour assurer ScrollViewer voit les évènements de la roue de la souris tout en préservant les autres pour les éléments enfants?

Edit: je viens d'apprendre que ListBox intégré ScrollViewer qui est probablement en train de voler les évènements de la roue au parent ScrollViewer et que la spécification d'un modèle de contrôle peut le désactiver. Je vais mettre à jour cette question si ça résout le problème.

28
demandé sur Tom 2013-01-16 02:59:29

4 réponses

Vous pouvez aussi créer un behavior et l'attacher au contrôle parent (dans lequel les événements de scroll devraient être présents).

// 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>
49
répondu JoeB 2013-04-19 17:21:08

Spécification ControlTemplate pour les Listbox ce qui n'inclut pas un ScrollViewer résout le problème. Voir cette réponse et ces deux pages MSDN pour plus d'informations:

ControlTemplate

zone de liste des Styles et des Modèles

12
répondu Tom 2017-05-23 11:54:19

je sais qu'il est un peu tard mais j'ai une autre solution qui a fonctionné pour moi. J'ai changé mon stackpanel/listbox pour un itemscontrol/grille. Je ne sais pas pourquoi les événements de scroll fonctionnent correctement mais ils le font dans mon cas.

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

devient

<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>
2
répondu sean.net 2015-05-21 11:01:30

une autre façon d'implémenter ceci, est de créer votre propre ScrollViewer comme ceci:

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);
    }
}
2
répondu kahr 2015-06-08 11:23:09