Silverlight ScrollViewerをスクロールして、フォーカスを持つ子コントロールを表示するにはどうすればよいですか?
-
22-07-2019 - |
質問
複数のコントロールを含むグリッドを含むScrollViewerがあります。ユーザーはコントロールをタブで移動できますが、最終的には表示されていないコントロールにタブで移動します。そのため、コントロールを再度表示するには手作業でスクロールする必要があります。
ScrollViewerを自動的にスクロールして、フォーカスされたコントロールが常に表示されるようにする方法はありますか。それに失敗すると、すべてのコントロールでGotFocusイベントをリッスンし、ScrollViewerをスクロールしてコントロールを表示する以外に、この作業を行う方法はありますか?
現在、Silverlight 2を使用しています。
解決
Silverlight 3を使用してこれをテストしました。SL2についてはわかりません。
これは私の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に到達するまでタブを押すことでした。それは私のために働いた。試してみて、どのように機能するか教えてください。
他のヒント
silverlightツールキットには、メソッド&quot; ScrollIntoView&quot;が含まれています。
System.Windows.Controls.Toolkit.dll ansへの参照を追加して、以下のコードを使用できるようにします。
scrollViewer.ScrollIntoView(control);
わずかに強化されました。ちなみに、Silverlight 4でもこれを行う必要があります。 各コントロールのGotFocusの代わりに、スクロールビューアー自体の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
}
上記のキリルの答えを参考に、これを機能させました。これの一般的なコンテキストは、アプリケーションにユーザー定義可能なフォームがあり、このコードはフォーム上のコントロールをレンダリングするために使用されるということです。
私の一般的な戦略は、コントロールをグリッドに追加し、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クラスに便利な検索機能を追加する独自のクラスです。