¿Cómo puedo hacer que Silverlight ScrollViewer se desplace para mostrar un control secundario con enfoque?

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

  •  22-07-2019
  •  | 
  •  

Pregunta

Tengo un ScrollViewer que contiene una cuadrícula con múltiples controles. El usuario puede tabular a través de los controles, pero eventualmente se tabula a un control que no está a la vista, por lo que tiene que desplazarse manualmente para que el control sea visible nuevamente.

¿Hay alguna manera de hacer que el ScrollViewer se desplace automáticamente para que el control enfocado esté siempre visible? De lo contrario, ¿hay alguna forma de hacer que esto funcione, sin escuchar un evento GotFocus en cada control y luego desplazar el ScrollViewer para que el control sea visible?

Actualmente estoy usando Silverlight 2.

¿Fue útil?

Solución

Probé esto con Silverlight 3. No estoy seguro acerca de SL2.

Este es mi 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>

Y este es el código subyacente:

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

Lo que hice fue hacer clic en el Botón # 1 y la pestaña hasta llegar al Botón # 20. Funcionó para mi. Pruébelo y dígame cómo funciona para usted.

Otros consejos

El kit de herramientas de Silverlight contiene un método " ScrollIntoView " ;.

Agregue una referencia a System.Windows.Controls.Toolkit.dll y debería poder usar el código a continuación.

scrollViewer.ScrollIntoView(control);

Solo una ligera mejora. Todavía tengo que hacer esto para Silverlight 4 por cierto. En lugar de GotFocus para cada control, puede manejar el GotFocus del propio scrollviewer e implementarlo solo una vez.

 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
        }

Conseguí que esto funcionara, con la ayuda de la respuesta de Kiril anterior. El contexto general de esto es que tengo formularios definibles por el usuario en mi aplicación, y este código se usa para representar los controles en un formulario.

Mi estrategia general era agregar mis controles a una cuadrícula, luego encontrar todos los elementos secundarios del ScrollViewer usando VisualTreeHelper y agregar un controlador de eventos GotFocus a cada control.

Cuando el control obtiene el foco, nuevamente usando VisualTreeHelper, busco en el árbol visual para encontrar el control cuyo padre es la Cuadrícula que ScrollViewer está desplazando. Luego, desplazo el ScrollViewer para que el control sea visible.

Aquí está el código (gridRender es la cuadrícula a la que se agregan los controles):

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

Nota: la clase VisualTreeHelperUtil es mi propia clase que agrega algunas funciones de búsqueda útiles a la clase VisualTreeHelper.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top