代码之家  ›  专栏  ›  技术社区  ›  Craig Shearer

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

  •  13
  • Craig Shearer  · 技术社区  · 16 年前

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

    是否有任何方法使ScrollViewer自动滚动,以便焦点控件始终可见。如果不能做到这一点,是否有任何方法可以实现这一点,除了在每个控件上侦听gotfocus事件,然后滚动ScrollViewer以使控件可见之外?

    目前我正在使用Silverlight2。

    4 回复  |  直到 13 年前
        1
  •  12
  •   Kiril Stanoev    16 年前

    我用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。这对我很有用。试一试,让我知道它是如何为你工作的。

        2
  •  11
  •   olorin    15 年前

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

    添加对system.windows.controls.toolkit.dll的引用,您应该能够使用下面的代码。

    scrollViewer.ScrollIntoView(control);

        3
  •  3
  •   Brian    16 年前

    只是轻微的增强。顺便说一下,对于Silverlight4仍然需要这样做。 您可以处理ScrollViewer本身的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
            }
    
        4
  •  1
  •   Craig Shearer    16 年前

    在上面基里尔的回答的帮助下,我把这个问题解决了。一般情况下,我的应用程序中有用户可定义的表单,并且此代码用于呈现表单上的控件。

    我的一般策略是将控件添加到网格中,然后使用VisualTreeHelper查找ScrollViewer的所有子级,并向每个控件添加GotFocus事件处理程序。

    当控件获得焦点时,再次使用VisualTreeHelper,我搜索可视化树以查找其父级是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类添加了一些有用的搜索功能。