如何使Silverlight ScrollViewer滚动以显示具有焦点的子控件?

时间:2009-08-04 01:01:37

标签: silverlight scrollviewer

我有一个ScrollViewer,其中包含一个包含多个控件的Grid。用户可以通过控件进行制表,但最终它们会切换到不在视图中的控件 - 因此他们必须进行手动滚动以使控件再次可见。

有没有办法让ScrollViewer自动滚动,以便始终可以看到聚焦控件。如果失败了,有没有什么方法可以让这个工作,除了在每个控件上听一个GotFocus事件,然后滚动ScrollViewer使控件可见?

目前我正在使用Silverlight 2。

4 个答案:

答案 0 :(得分:12)

我使用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。它对我有用。试一试,让我知道它对你有用。

答案 1 :(得分:11)

silverlight工具包包含一个方法“ScrollIntoView”。

添加对System.Windows.Controls.Toolkit.dll的引用,你应该可以使用下面的代码。

scrollViewer.ScrollIntoView(control);

答案 2 :(得分:3)

稍微增强一点。仍然需要为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
        }

答案 3 :(得分:1)

在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类添加了一些有用的搜索功能。