我有一个 ScrollViewer,其中包含一个包含多个控件的 Grid。用户可以通过选项卡浏览控件,但最终他们将选项卡转到不在视图中的控件 - 因此他们必须手动滚动以使控件再次可见。
有什么方法可以使 ScrollViewer 自动滚动,以便始终可见焦点控件。如果做不到这一点,有什么办法可以让这个工作,除了在每个控件上监听 GotFocus 事件,然后滚动 ScrollViewer 以使控件可见?
目前我正在使用 Silverlight 2。
我有一个 ScrollViewer,其中包含一个包含多个控件的 Grid。用户可以通过选项卡浏览控件,但最终他们将选项卡转到不在视图中的控件 - 因此他们必须手动滚动以使控件再次可见。
有什么方法可以使 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);
}
我所做的是单击 Button #1 和 tab,直到我到达 Button #20。它对我有用。试一试,让我知道它是如何为你工作的。
silverlight 工具包包含一个方法“ScrollIntoView”。
添加对 System.Windows.Controls.Toolkit.dll 的引用,您应该可以使用下面的代码。
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
}
在上面 Kiril 的回答的帮助下,我得到了这个工作。一般情况下,我的应用程序中有用户可定义的表单,并且此代码用于呈现表单上的控件。
我的一般策略是将控件添加到 Grid,然后使用 VisualTreeHelper 查找 ScrollViewer 的所有子项,并为每个控件添加 GotFocus 事件处理程序。
当控件获得焦点时,再次使用 VisualTreeHelper,我搜索可视化树以查找其父控件是 ScrollViewer 正在滚动的 Grid 的控件。然后我滚动 ScrollViewer 以使控件可见。
这是代码(gridRender 是添加控件的 Grid):
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 类添加了一些有用的搜索功能。