2009-08-04 6 views
13

Ich habe einen ScrollViewer, der ein Grid mit mehreren Steuerelementen enthält. Der Benutzer kann durch die Steuerelemente navigieren, aber schließlich werden sie zu einem Steuerelement verschoben, das nicht angezeigt wird. Sie müssen also manuell scrollen, um das Steuerelement wieder sichtbar zu machen.Wie kann ich den Silverlight ScrollViewer scrollen, um ein untergeordnetes Steuerelement mit Fokus anzuzeigen?

Gibt es eine Möglichkeit, den ScrollViewer automatisch scrollen zu lassen, so dass das fokussierte Steuerelement immer sichtbar ist. Sollte ich das nicht schaffen, kann ich das irgendwie schaffen, wenn ich nicht auf ein GotFocus-Ereignis auf jedem Steuerelement lausche und dann den ScrollViewer scrolle, um das Steuerelement sichtbar zu machen?

Derzeit bin ich mit Silverlight 2.

Antwort

12

Getestet habe ich diese mit Silverlight 3. Ich über SL2 nicht sicher bin.

Das ist mein 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> 

Und dies ist der 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); 
} 

Was ich tat, auf die Taste 1 und Reiter klicken, bis ich zu Button # bekommen 20. Es hat für mich funktioniert. Probieren Sie es aus und lassen Sie mich wissen, wie es für Sie funktioniert.

+0

Dank - mit einer kleinen Änderung, die ich als Antwort schreiben würde, es funktionierte sehr gut. Die TransformBounds-Methode für GeneralTransform scheint jedoch eine SL3-Sache zu sein. –

+0

Ich weiß, das ist ein alter Beitrag, aber ich versuche das Gleiche zu tun. Ich verwende diesen Code, aber die Werte für Margin.Left und Margin.Top sind immer 0.Das Steuerelement, zu dem ich blättern möchte, befindet sich in einem Raster im ScrollViewer, und das Steuerelement wird im Raster positioniert, indem ihm ein Zeilen- und Zeilenbereichseigenschaftswert zugewiesen wird. – Jeremy

1

Ich habe dies mit Hilfe von Kirils Antwort oben zu arbeiten. Der allgemeine Kontext davon ist, dass ich benutzerdefinierte Formulare in meiner Anwendung habe und dieser Code zum Rendern der Steuerelemente in einem Formular verwendet wird.

Meine allgemeine Strategie bestand darin, meine Steuerelemente zu einem Raster hinzuzufügen, dann alle untergeordneten Elemente des ScrollViewers mit VisualTreeHelper zu finden und jedem Steuerelement einen GotFocus-Ereignishandler hinzuzufügen.

Wenn das Steuerelement den Fokus wieder mit VisualTreeHelper erhält, suche ich den visuellen Baum nach dem Steuerelement, dessen Eltern das Raster ist, das durch den ScrollViewer gescrollt wird. Dann scrolle ich den ScrollViewer, um das Steuerelement sichtbar zu machen.

Hier ist der Code (gridRender das Gitter ist, dass die Kontrollen werden hinzugefügt):

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

Hinweis: Die VisualTreeHelperUtil Klasse meine eigene Klasse, die einige nützliche Suchfunktionalität auf die VisualTreeHelper Klasse hinzufügt.

3

Nur eine kleine Verbesserung. Das musst du übrigens auch für Silverlight 4 tun. Anstelle von GotFocus für jedes Steuerelement können Sie den GotFocus des Scrollviewer selbst handhaben und ihn nur einmal implementieren.

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

Das silverlight Toolkit enthält eine Methode "ScrollIntoView".

Fügen Sie einen Verweis auf System.Windows.Controls.Toolkit.dll hinzu und Sie sollten den folgenden Code verwenden können.

scrollViewer.ScrollIntoView(control);

Verwandte Themen