【问题标题】:How can I make the Silverlight ScrollViewer scroll to show a child control with focus?如何使 Silverlight ScrollViewer 滚动以显示具有焦点的子控件?
【发布时间】:2009-08-04 01:01:36
【问题描述】:

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

有什么方法可以让 ScrollViewer 自动滚动,以便始终可见焦点控件。如果做不到这一点,除了在每个控件上侦听 GotFocus 事件然后滚动 ScrollViewer 以使控件可见之外,有什么方法可以使这项工作正常进行吗?

目前我使用的是 Silverlight 2。

【问题讨论】:

    标签: silverlight scrollviewer


    【解决方案1】:

    我使用 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。它对我有用。试一试,告诉我它对你有什么作用。

    【讨论】:

    • 谢谢 - 稍作修改,我将作为答案发布,它工作得非常好。不过,GeneralTransform 上的 TransformBounds 方法似乎是 SL3 的东西。
    • 我知道这是一篇旧帖子,但我正在尝试做同样的事情。我正在使用此代码,但 Margin.Left 和 Margin.Top 值始终为 0。我要滚动到的控件位于 ScrollViewer 的网格内,并且控件通过为其提供行和行跨度来定位在网格中属性值。
    【解决方案2】:

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

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

    scrollViewer.ScrollIntoView(control);

    【讨论】:

      【解决方案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
              }
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2012-01-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多