2009-08-04 16 views
13

Tengo un ScrollViewer que contiene una cuadrícula con múltiples controles. El usuario puede desplazarse a través de los controles, pero eventualmente tabulan un control que no está a la vista, por lo que tienen que desplazarse manualmente para hacer visible el control nuevamente.¿Cómo puedo hacer que el Silverlight ScrollViewer se desplace para mostrar un control secundario con foco?

¿Hay alguna manera de hacer que ScrollViewer se desplace automáticamente para que el control enfocado siempre esté visible? En su defecto, ¿hay alguna forma de que pueda hacer esto, excepto escuchar un evento GotFocus en cada control y luego desplazar el ScrollViewer para hacer visible el control?

En la actualidad estoy usando Silverlight 2.

Respuesta

12

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

Esta 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 que llegue al botón # 20. Funcionó para mí Pruébalo y cuéntame cómo te funciona.

+0

Gracias - con una pequeña modificación, que voy a publicar como respuesta, funcionó muy bien. El método TransformBounds en GeneralTransform parece ser una cosa SL3 sin embargo. –

+0

Sé que esta es una publicación anterior, pero estoy tratando de hacer lo mismo. Estoy usando este código pero los valores Margin.Left y Margin.Top siempre son 0.El control que quiero desplazar está dentro de una cuadrícula en ScrollViewer, y el control se posiciona en la cuadrícula dándole un valor de propiedad row y rowspan. – Jeremy

1

Lo hice funcionar, con la ayuda de la respuesta de Kiril anterior. El contexto general de esto es que tengo formularios definidos 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 de ScrollViewer usando VisualTreeHelper, y agregar un manejador de eventos GotFocus a cada control.

Cuando el control se enfoca, de nuevo usando VisualTreeHelper, busco el árbol visual para encontrar el control cuyo elemento principal es la Cuadrícula que está siendo desplazada por el ScrollViewer. Luego, desplazo el ScrollViewer para hacer visible el control.

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

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 añade algunas funciones de búsqueda útil para la clase VisualTreeHelper.

3

Solo una ligera mejora. Todavía tengo que hacer esto para Silverlight 4 por cierto. En lugar de GotFocus para cada control, puede manejar GotFocus del 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 
     } 
11

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

añadir una referencia a la American National Standard System.Windows.Controls.Toolkit.dll usted debería ser capaz de utilizar el código de abajo.

scrollViewer.ScrollIntoView(control);

Cuestiones relacionadas