我想在的ScrollViewer内的ListView到中心选定的项目,并奋力计算垂直偏移,我应该在的ScrollViewer相对于ListView控件进行设置。
以下链接让我在正确的轨道上,但由于的WinRT API的限制,无法使用它们:
- 使ListView.ScrollIntoView滚动项目到ListView中的中心(C#)
- 的 blogs.msdn/b/delay/archive/ 2009年/ 04/19 /更少-陷阱对俘获增强最scrollintoviewcentered法换WPF-S-listbox.aspx
期望的效果如下:
这是我的XAML示例设置:
<的ScrollViewer X:NAME =MyScrollViewer> < ListView的X:名称=MyView的VerticalAlignment =中心的SelectionChanged =Selector_OnSelectionChanged> < ListView.ItemTemplate> <&DataTemplate的GT; <电网WIDTH =80HEIGHT =80保证金=0> < TextBlock的文本={结合}/> < /网格和GT; < / DataTemplate中> < /ListView.ItemTemplate> < ListView.Items> 将; X:字符串→1&下; / X:字符串> 将; X:字符串→2&下; / X:字符串> 将; X:字符串→3&下; / X:字符串> 将; X:字符串→4&下; / X:字符串> 将; X:字符串> 5℃/ X:字符串> 将; X:字符串→6&下; / X:字符串> 将; X:字符串大于7&下; / X:字符串> 将; X:字符串→8&下; / X:字符串> < X:字符串> 9< / X:字符串> < /ListView.Items> < /&的ListView GT; < /&的ScrollViewer GT;
了解所选项目的索引,我该如何计算垂直偏移,我可以用我的方法:
Selector_OnSelectionChanged私人无效(对象发件人,SelectionChangedEventArgs E) {双maxVerticalOffset = MyScrollViewer。 ExtentHeight - MyScrollViewer.ViewportHeight; INT selectedItemIndex = MyView.SelectedIndex; 双verticalOffset = ... MyScrollViewer.ChangeView(NULL,verticalOffset,NULL); }解决方案
尝试的 ListView.ScrollIntoView() 或 ListView.MakeVisible 第一个项目的容器滚动到视图和工作围绕它可能正在从虚拟化的UI。然后使用的 ListView.ItemContainerGenerator 。的 ContainerFromIndex ()获得该项目的容器,然后在 VisualTreeHelper 来获取相对于的ScrollViewer 的位置。然后滚动通过将计算抵消的ScrollViewer
*编辑 - 举例定位逻辑:
获得 VisualTreeHelperExtensions从WinRT的XAML工具包来获得访问在的ScrollViewer 容易与封装到 VisualTreeHelper 几个电话 GetFirstDescendantOfType()扩展方法code>。
XAML
<第X:类=ListViewItemCentering.MainPage的xmlns =schemas.microsoft/winfx/2006/xaml/presentation的xmlns:X =schemas.microsoft/winfx/2006/xaml的xmlns:本地=使用:ListViewItemCentering的xmlns:D =schemas.microsoft/表达/混合/ 2008的xmlns:MC =schemas.openxmlformats/markup-compatibility/2006 MC:可忽略=D> <电网背景={ThemeResource ApplicationPageBackgroundThemeBrush}> < ListView的 X:NAME =ListView控件> < ListView.ItemTemplate> <&DataTemplate的GT; < BORDER WIDTH =400 HEIGHT =100> < ContentControl中含量={结合}字号=48填充=20,10/> < /边框> < / DataTemplate中> < /ListView.ItemTemplate> < /&的ListView GT; <按钮含量=跳过 WIDTH =200 HEIGHT =100的HorizontalAlignment =右 VerticalAlignment =底点击=ButtonBase_OnClick/> < /网格和GT; < /页>
C#
使用系统; 使用System.Collections.Generic; 使用System.Linq的;使用System.Threading.Tasks ; 使用Windows.Foundation; 使用Windows.UI.Xaml;使用Windows.UI.Xaml.Controls ;使用WinRTXamlToolkit.Controls.Extensions ; 命名空间ListViewItemCentering { ///<总结> ///可以在自己的一个框架内使用或导航到一个空白页。 ///< /总结> 公共密封部分类的MainPage:第 {私人随机随机=新的随机(); 公众的MainPage() { this.InitializeComponent(); this.listView.ItemsSource = Enumerable.Range(1,1000); this.listView.SelectionChanged + = OnListViewSelectionChanged; } 私人异步无效OnListViewSelectionChanged(对象发件人,SelectionChangedEventArgs selectionChangedEventArgs) {如果(listView.SelectedItem == NULL) {返回; } VAR项目= listView.SelectedItem; //计算相对于屏幕或ListView VAR的ListViewItem =(FrameworkElement的)listView.ContainerFromItem(项目); 如果(ListViewItem的== NULL) { listView.ScrollIntoView(项目); } ,而(ListViewItem的== NULL) {等待Task.Delay(1); //等待滚动完成 - 它需要一段时间的ListViewItem =(FrameworkElement的)listView.ContainerFromItem(项目); } 变种左上= ListViewItem的 .TransformToVisual(ListView控件) .TransformPoint(新点())Y。 VAR lvih = listViewItem.ActualHeight; VAR肥厚= listView.ActualHeight; VAR desiredTopLeft =(LVH - lvih)/ 2.0; VAR desiredDelta =左上 - desiredTopLeft; //计算相对ListView的 VAR内向的ScrollViewer的ScrollViewer = listView.GetFirstDescendantOfType<&的ScrollViewer GT;(); VAR currentOffset = scrollViewer.VerticalOffset; VAR desiredOffset = currentOffset + desiredDelta; scrollViewer.ScrollToVerticalOffset(desiredOffset); //更好,但如果建设为Windows 8.1,使滚动更流畅的使用: // scrollViewer.ChangeView(NULL,desiredOffset,NULL); } 私人异步无效ButtonBase_OnClick(对象发件人,RoutedEventArgs E) { this.listView.SelectedIndex = random.Next(0,((IEnumerable的< INT> ;)this.listView.ItemsSource).Count之间的()); } } }
I am trying to center a selected item in a ListView inside a ScrollViewer and struggling to calculate the vertical offset that I should be setting the ScrollViewer relative to the ListView.
The following links set me on the right track, but because of the limitation of the WinRT API, was not able to use them:
- Make ListView.ScrollIntoView Scroll the Item into the Center of the ListView (C#)
- blogs.msdn/b/delay/archive/2009/04/19/fewer-gotchas-to-getcha-enhancing-the-scrollintoviewcentered-method-for-wpf-s-listbox.aspx
The desired effect is as follows:
This is a sample setup in my XAML:
<ScrollViewer x:Name="MyScrollViewer"> <ListView x:Name="MyView" VerticalAlignment="Center" SelectionChanged="Selector_OnSelectionChanged"> <ListView.ItemTemplate> <DataTemplate> <Grid Width="80" Height="80" Margin="0"> <TextBlock Text="{Binding}" /> </Grid> </DataTemplate> </ListView.ItemTemplate> <ListView.Items> <x:String>1</x:String> <x:String>2</x:String> <x:String>3</x:String> <x:String>4</x:String> <x:String>5</x:String> <x:String>6</x:String> <x:String>7</x:String> <x:String>8</x:String> <x:String>9</x:String> </ListView.Items> </ListView> </ScrollViewer>Knowing the index of the selected item, how do I calculate the vertical offset that I can use in my method:
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { double maxVerticalOffset = MyScrollViewer.ExtentHeight - MyScrollViewer.ViewportHeight; int selectedItemIndex = MyView.SelectedIndex; double verticalOffset = ... MyScrollViewer.ChangeView(null, verticalOffset, null); }解决方案
Try ListView.ScrollIntoView() or ListView.MakeVisible first to scroll the container of the item into view and work around it being possibly virtualized out of the UI. Then use ListView.ItemContainerGenerator.ContainerFromIndex() to get the container of the item and then the VisualTreeHelper to get its position relative to the ScrollViewer. Then scroll the scrollviewer by the calculated offset.
*EDIT - Example positioning logic:
Get the VisualTreeHelperExtensions from WinRT XAML Toolkit to get access to the ScrollViewer easily with GetFirstDescendantOfType() extension method that wraps some calls to the VisualTreeHelper.
XAML
<Page x:Class="ListViewItemCentering.MainPage" xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/winfx/2006/xaml" xmlns:local="using:ListViewItemCentering" xmlns:d="schemas.microsoft/expression/blend/2008" xmlns:mc="schemas.openxmlformats/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <ListView x:Name="listView"> <ListView.ItemTemplate> <DataTemplate> <Border Width="400" Height="100"> <ContentControl Content="{Binding}" FontSize="48" Padding="20,10"/> </Border> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button Content="Skip" Width="200" Height="100" HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="ButtonBase_OnClick"/> </Grid> </Page>C#
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using WinRTXamlToolkit.Controls.Extensions; namespace ListViewItemCentering { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page { private Random random = new Random(); public MainPage() { this.InitializeComponent(); this.listView.ItemsSource = Enumerable.Range(1, 1000); this.listView.SelectionChanged += OnListViewSelectionChanged; } private async void OnListViewSelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) { if (listView.SelectedItem == null) { return; } var item = listView.SelectedItem; // Calculations relative to screen or ListView var listViewItem = (FrameworkElement)listView.ContainerFromItem(item); if (listViewItem == null) { listView.ScrollIntoView(item); } while (listViewItem == null) { await Task.Delay(1); // wait for scrolling to complete - it takes a moment listViewItem = (FrameworkElement)listView.ContainerFromItem(item); } var topLeft = listViewItem .TransformToVisual(listView) .TransformPoint(new Point()).Y; var lvih = listViewItem.ActualHeight; var lvh = listView.ActualHeight; var desiredTopLeft = (lvh - lvih) / 2.0; var desiredDelta = topLeft - desiredTopLeft; // Calculations relative to the ScrollViewer within the ListView var scrollViewer = listView.GetFirstDescendantOfType<ScrollViewer>(); var currentOffset = scrollViewer.VerticalOffset; var desiredOffset = currentOffset + desiredDelta; scrollViewer.ScrollToVerticalOffset(desiredOffset); // better yet if building for Windows 8.1 to make the scrolling smoother use: // scrollViewer.ChangeView(null, desiredOffset, null); } private async void ButtonBase_OnClick(object sender, RoutedEventArgs e) { this.listView.SelectedIndex = random.Next(0, ((IEnumerable<int>)this.listView.ItemsSource).Count()); } } }
更多推荐
定心在涡旋观众选择项
发布评论