Comment faire défiler le Silverlight ScrollViewer pour afficher un contrôle enfant avec focus?

StackOverflow https://stackoverflow.com/questions/1225318

  •  22-07-2019
  •  | 
  •  

Question

J'ai un ScrollViewer qui contient une grille avec plusieurs contrôles. L'utilisateur peut faire défiler les contrôles, mais finalement, ils choisissent un contrôle qui n'est pas visible - ils doivent donc faire défiler l'écran pour rendre le contrôle visible à nouveau.

Existe-t-il un moyen de faire défiler automatiquement ScrollViewer de sorte que le contrôle ciblé soit toujours visible. Sinon, y a-t-il un moyen que je puisse faire en sorte que cela fonctionne, à part écouter un événement GotFocus sur chaque contrôle puis faire défiler le ScrollViewer pour le rendre visible?

Actuellement, j'utilise Silverlight 2.

Était-ce utile?

La solution

J'ai testé cela avec Silverlight 3. Je ne suis pas sûr de SL2.

Ceci est mon XAML:

<ScrollViewer Height="200" Width="200" KeyUp="ScrollViewer_KeyUp">
    <StackPanel>
        <Button Content="1" Height="20" />
        <Button Content="2" Height="20" />
        <Button Content="3" Height="20" />
        <Button Content="4" Height="20" />
        <Button Content="5" Height="20" />
        <Button Content="6" Height="20" />
        <Button Content="7" Height="20" />
        <Button Content="8" Height="20" />
        <Button Content="9" Height="20" />
    <Button Content="10" Height="20" />
        <Button Content="11" Height="20" />
        <Button Content="12" Height="20" />
        <Button Content="13" Height="20" />
        <Button Content="14" Height="20" />
        <Button Content="15" Height="20" />
        <Button Content="16" Height="20" />
        <Button Content="17" Height="20" />
        <Button Content="18" Height="20" />
        <Button Content="19" Height="20" />
        <Button Content="20" Height="20" />
    </StackPanel>
</ScrollViewer>

Et voici le code-behind:

private void ScrollViewer_KeyUp(object sender, KeyEventArgs e)
{
    ScrollViewer scrollViewer = sender as ScrollViewer;
    FrameworkElement focusedElement = FocusManager.GetFocusedElement() as FrameworkElement;
    GeneralTransform focusedVisualTransform = focusedElement.TransformToVisual(scrollViewer);
    Rect rectangle = focusedVisualTransform.TransformBounds(new Rect(new Point(focusedElement.Margin.Left, focusedElement.Margin.Top), focusedElement.RenderSize));
    double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);
    scrollViewer.ScrollToVerticalOffset(newOffset);
}

Ce que j’ai fait, c’est de cliquer sur le bouton n ° 1, puis sur l’onglet jusqu’à atteindre le bouton n ° 20. Cela a fonctionné pour moi. Essayez-le et laissez-moi savoir comment cela fonctionne pour vous.

Autres conseils

La boîte à outils silverlight contient une méthode "ScrollIntoView".

Ajoutez une référence à System.Windows.Controls.Toolkit.dll et vous devriez pouvoir utiliser le code ci-dessous.

scrollViewer.ScrollIntoView (control);

Juste une légère amélioration. Encore faut-il le faire pour Silverlight 4 au fait. Au lieu de GotFocus pour chaque contrôle, vous pouvez gérer le GotFocus du scrollviewer lui-même et le mettre en œuvre une seule fois.

 private void _ScrollViewer_GotFocus(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = e.OriginalSource as FrameworkElement;

            if (element != null)
            {
                ScrollViewer scrollViewer = sender as ScrollViewer;
                scrollViewer.ScrollToVerticalOffset(GetVerticalOffset(element, scrollViewer));
            }

        }

        private double GetVerticalOffset(FrameworkElement child, ScrollViewer scrollViewer)
        {
            // Ensure the control is scrolled into view in the ScrollViewer. 
            GeneralTransform focusedVisualTransform = child.TransformToVisual(scrollViewer);
            Point topLeft = focusedVisualTransform.Transform(new Point(child.Margin.Left, child.Margin.Top));
            Rect rectangle = new Rect(topLeft, child.RenderSize);
            double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);
            return newOffset < 0 ? 0 : newOffset; // no use returning negative offset
        }

J'ai réussi à faire fonctionner cela avec l'aide de la réponse de Kiril ci-dessus. Le contexte général de cette opération est que mon application contient des formulaires que l'utilisateur peut définir, et que ce code est utilisé pour rendre les contrôles d'un formulaire.

Ma stratégie générale consistait à ajouter mes contrôles à une grille, puis à rechercher tous les enfants de ScrollViewer à l'aide de VisualTreeHelper et à ajouter un gestionnaire d'événements GotFocus à chaque contrôle.

Lorsque le contrôle obtient le focus, toujours à l'aide de VisualTreeHelper, je recherche dans l'arborescence visuelle pour trouver le contrôle dont le parent est la grille défilée par ScrollViewer. Ensuite, je fais défiler ScrollViewer pour rendre le contrôle visible.

Voici le code (gridRender est la grille à laquelle les contrôles sont ajoutés):

private void AfterFormRendered()
{
    var controls = VisualTreeHelperUtil.FindChildren<Control>(gridRender);
    foreach (var ctrl in controls)
    {
        ctrl.GotFocus += CtrlGotFocus;
    }
}

private void CtrlGotFocus(object sender, RoutedEventArgs e)
{
    var ctrl = sender as Control;
    var gridChildControl = VisualTreeHelperUtil.FindParentWithParent(ctrl, gridRender) as FrameworkElement;

    if (gridChildControl != null)
    {
        // Ensure the control is scrolled into view in the ScrollViewer.
        GeneralTransform focusedVisualTransform = gridChildControl.TransformToVisual(scrollViewer);
        Point topLeft = focusedVisualTransform.Transform(new Point(gridChildControl.Margin.Left, gridChildControl.Margin.Top));
        Rect rectangle = new Rect(topLeft, gridChildControl.RenderSize);
        double newOffset = scrollViewer.VerticalOffset + (rectangle.Bottom - scrollViewer.ViewportHeight);    

        scrollViewer.ScrollToVerticalOffset(newOffset);
    }
}

Remarque: la classe VisualTreeHelperUtil est ma propre classe, qui ajoute des fonctionnalités de recherche utiles à la classe VisualTreeHelper.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top