为了账号安全,请及时绑定邮箱和手机立即绑定

使ListView.ScrollIntoView滚动项目到ListView(C#)的中心

使ListView.ScrollIntoView滚动项目到ListView(C#)的中心

C#
临摹微笑 2019-12-26 14:07:33
ListView.ScrollIntoView(object)当前在中找到一个对象ListView并滚动到该对象。如果您位于要滚动到的对象下方,它将滚动该对象到第一行。如果您位于上方,则将其滚动到底部行的视图中。如果当前不可见,我想使该项目滚动到列表视图的中心。有没有简单的方法可以做到这一点?
查看完整描述

3 回答

?
撒科打诨

TA贡献1934条经验 获得超2个赞

在WPF中使用我编写的扩展方法很容易做到这一点。将项目滚动到视图中心所需要做的就是调用一个方法。


假设您有以下XAML:


<ListView x:Name="view" ItemsSource="{Binding Data}" /> 

<ComboBox x:Name="box"  ItemsSource="{Binding Data}"

                        SelectionChanged="ScrollIntoView" /> 

您的ScrollIntoView方法将很简单:


private void ScrollIntoView(object sender, SelectionChangedEventArgs e)

{

  view.ScrollToCenterOfView(box.SelectedItem);

显然,这也可以使用ViewModel来完成,而不是显式地引用控件。


以下是实现。非常通用,可以处理所有IScrollInfo可能性。它可以与ListBox或任何其他ItemsControl一起使用,并且可以与任何面板一起使用,包括StackPanel,VirtualizingStackPanel,WrapPanel,DockPanel,Canvas,Grid等。


只需将其放入项目中某个.cs文件中即可:


public static class ItemsControlExtensions

{

  public static void ScrollToCenterOfView(this ItemsControl itemsControl, object item)

  {

    // Scroll immediately if possible

    if(!itemsControl.TryScrollToCenterOfView(item))

    {

      // Otherwise wait until everything is loaded, then scroll

      if(itemsControl is ListBox) ((ListBox)itemsControl).ScrollIntoView(item);

      itemsControl.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>

        {

          itemsControl.TryScrollToCenterOfView(item);

        }));

    }

  }


  private static bool TryScrollToCenterOfView(this ItemsControl itemsControl, object item)

  {

    // Find the container

    var container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement;

    if(container==null) return false;


    // Find the ScrollContentPresenter

    ScrollContentPresenter presenter = null;

    for(Visual vis = container; vis!=null && vis!=itemsControl; vis = VisualTreeHelper.GetParent(vis) as Visual)

      if((presenter = vis as ScrollContentPresenter)!=null)

        break;

    if(presenter==null) return false;


    // Find the IScrollInfo

    var scrollInfo = 

        !presenter.CanContentScroll ? presenter :

        presenter.Content as IScrollInfo ??

        FirstVisualChild(presenter.Content as ItemsPresenter) as IScrollInfo ??

        presenter;


    // Compute the center point of the container relative to the scrollInfo

    Size size = container.RenderSize;

    Point center = container.TransformToAncestor((Visual)scrollInfo).Transform(new Point(size.Width/2, size.Height/2));

    center.Y += scrollInfo.VerticalOffset;

    center.X += scrollInfo.HorizontalOffset;


    // Adjust for logical scrolling

    if(scrollInfo is StackPanel || scrollInfo is VirtualizingStackPanel)

    {

      double logicalCenter = itemsControl.ItemContainerGenerator.IndexFromContainer(container) + 0.5;

      Orientation orientation = scrollInfo is StackPanel ? ((StackPanel)scrollInfo).Orientation : ((VirtualizingStackPanel)scrollInfo).Orientation;

      if(orientation==Orientation.Horizontal)

        center.X = logicalCenter;

      else

        center.Y = logicalCenter;

    }


    // Scroll the center of the container to the center of the viewport

    if(scrollInfo.CanVerticallyScroll) scrollInfo.SetVerticalOffset(CenteringOffset(center.Y, scrollInfo.ViewportHeight, scrollInfo.ExtentHeight));

    if(scrollInfo.CanHorizontallyScroll) scrollInfo.SetHorizontalOffset(CenteringOffset(center.X, scrollInfo.ViewportWidth, scrollInfo.ExtentWidth));

    return true;

  }


  private static double CenteringOffset(double center, double viewport, double extent)

  {

    return Math.Min(extent - viewport, Math.Max(0, center - viewport/2));

  }

  private static DependencyObject FirstVisualChild(Visual visual)

  {

    if(visual==null) return null;

    if(VisualTreeHelper.GetChildrenCount(visual)==0) return null;

    return VisualTreeHelper.GetChild(visual, 0);

  }

}


查看完整回答
反对 回复 2019-12-26
?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

上面的Ray Burns出色的答案是WPF特有的。


这是在Silverlight中可以使用的修改后的版本:


 public static class ItemsControlExtensions

    {

        public static void ScrollToCenterOfView(this ItemsControl itemsControl, object item)

        {

            // Scroll immediately if possible 

            if (!itemsControl.TryScrollToCenterOfView(item))

            {

                // Otherwise wait until everything is loaded, then scroll 

                if (itemsControl is ListBox) ((ListBox)itemsControl).ScrollIntoView(item);

                itemsControl.Dispatcher.BeginInvoke( new Action(() =>

                {

                    itemsControl.TryScrollToCenterOfView(item);

                }));

            }

        }


        private static bool TryScrollToCenterOfView(this ItemsControl itemsControl, object item)

        {

            // Find the container 

            var container = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement;

            if (container == null) return false;


            // Find the ScrollContentPresenter 

            ScrollContentPresenter presenter = null;

            for (UIElement vis = container; vis != null ; vis = VisualTreeHelper.GetParent(vis) as UIElement)

                if ((presenter = vis as ScrollContentPresenter) != null)

                    break;

            if (presenter == null) return false;


            // Find the IScrollInfo 

            var scrollInfo =

                !presenter.CanVerticallyScroll ? presenter :

                presenter.Content as IScrollInfo ??

                FirstVisualChild(presenter.Content as ItemsPresenter) as IScrollInfo ??

                presenter;


            // Compute the center point of the container relative to the scrollInfo 

            Size size = container.RenderSize;

            Point center = container.TransformToVisual((UIElement)scrollInfo).Transform(new Point(size.Width / 2, size.Height / 2));

            center.Y += scrollInfo.VerticalOffset;

            center.X += scrollInfo.HorizontalOffset;


            // Adjust for logical scrolling 

            if (scrollInfo is StackPanel || scrollInfo is VirtualizingStackPanel)

            {

                double logicalCenter = itemsControl.ItemContainerGenerator.IndexFromContainer(container) + 0.5;

                Orientation orientation = scrollInfo is StackPanel ? ((StackPanel)scrollInfo).Orientation : ((VirtualizingStackPanel)scrollInfo).Orientation;

                if (orientation == Orientation.Horizontal)

                    center.X = logicalCenter;

                else

                    center.Y = logicalCenter;

            }


            // Scroll the center of the container to the center of the viewport 

            if (scrollInfo.CanVerticallyScroll) scrollInfo.SetVerticalOffset(CenteringOffset(center.Y, scrollInfo.ViewportHeight, scrollInfo.ExtentHeight));

            if (scrollInfo.CanHorizontallyScroll) scrollInfo.SetHorizontalOffset(CenteringOffset(center.X, scrollInfo.ViewportWidth, scrollInfo.ExtentWidth));

            return true;

        }


        private static double CenteringOffset(double center, double viewport, double extent)

        {

            return Math.Min(extent - viewport, Math.Max(0, center - viewport / 2));

        }


        private static DependencyObject FirstVisualChild(UIElement visual)

        {

            if (visual == null) return null;

            if (VisualTreeHelper.GetChildrenCount(visual) == 0) return null;

            return VisualTreeHelper.GetChild(visual, 0);

        }

    } 


查看完整回答
反对 回复 2019-12-26
  • 3 回答
  • 0 关注
  • 803 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信