撒科打诨
在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); }}
汪汪一只猫
上面的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); } }