2009-08-04 13 views
13

複数のコントロールを含むグリッドを含むScrollViewerがあります。ユーザーはコントロールをタブすることができますが、最終的には表示されていないコントロールにタブが移動するため、再度スクロールしてコントロールを再び表示させる必要があります。Silverlight ScrollViewerのスクロールで、フォーカスのある子コントロールを表示するにはどうすればよいですか?

集束コントロールが常に表示されるように自動的にScrollViewerのスクロールを作成する方法はあります。それができない場合、コントロールを表示するためにScrollViewerをスクロールしてから、すべてのコントロールでGotFocusイベントを聴いていないのに、この作業を行う方法がありますか?

現時点では私は、Silverlight 2

答えて

12

を使用している私はSL2について確認していない、この使用してSilverlightの3テスト。

このは私の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> 

そして、これはコードビハインドである:

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

私はボタン#に到達するまでボタン#1とタブをクリックしていた私は何をやりました20。それは私のために働いた。試してみて、それがあなたのためにどのように働くか教えてください。

+0

おかげで - 少し修正して、私はそれが非常にうまく働いていた答えとして投稿します。 GeneralTransformのTransformBoundsメソッドはSL3のようです。 –

+0

これは古い投稿であることは分かっていますが、私は同じことをやろうとしています。私はこのコードを使用していますが、Margin.LeftとMargin.Topの値は常に0です。スクロールするコントロールはScrollViewerのグリッドの内側にあり、コントロールはグリッド内にrowとrowspanのプロパティ値を渡して配置されます。 – Jeremy

1

私は上記のKirilの答えの助けを借りて、これを動作させました。これの一般的なコンテキストは、アプリケーションでユーザー定義可能なフォームがあり、このコードはフォーム上のコントロールをレンダリングするために使用されるということです。

私の一般的な戦略は、グリッドに私のコントロールを追加しVisualTreeHelperを使用してScrollViewerののすべての子を見つけて、各コントロールにGotFocusイベントハンドラを追加することでした。

コントロールがVisualTreeHelperを使用して再度、フォーカスを取得したときに、私はその親ScrollViewerのでスクロールされるグリッドであるコントロールを見つけるために、ビジュアルツリーを検索します。次に、コントロールを表示させるためにScrollViewerをスクロールします。

はここ(gridRenderは、コントロールが追加されていることをグリッドである)コードです:

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

注:VisualTreeHelperUtilクラスはVisualTreeHelperクラスにいくつかの有用な検索機能を追加し、私自身のクラスです。

3

わずかに強化されています。 Silverlight 4ではまだこれを行う必要があります。 各コントロールのGotFocusの代わりに、scrollviewer自体のGotFocusを処理し、一度実装することができます。

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

silverlightツールキットには、メソッド "ScrollIntoView"が含まれています。

はSystem.Windows.Controls.Toolkit.dllへの参照を追加します。ANSあなたは以下のコードを使用することができるはずです。

scrollViewer.ScrollIntoView(control);

関連する問題