c# – ListBox ScrollIntoView当使用GroupViewSource与GroupDesc
短版
当选择更改时,我想将ListBox项目滚动到视图中. 长版 我有一个ListBox,ItemsSource绑定到一个GroupViewSource与一个GroupDescription,如下面的例子. <Window.Resources> <CollectionViewSource x:Key="AnimalsView" Source="{Binding Source={StaticResource Animals},Path=AnimalList}"> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName="Category"/> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </Window.Resources> <ListBox x:Name="AnimalsListBox"ItemsSource="{Binding Source={StaticResource AnimalsView}}" ItemTemplate="{StaticResource AnimalTemplate}" SelectionChanged="ListBox_SelectionChanged"> <ListBox.GroupStyle> <GroupStyle HeaderTemplate="{StaticResource CategoryTemplate}" /> </ListBox.GroupStyle> </ListBox> 代码隐藏文件中有一个SelectionChanged事件. public List<Animal> Animals { get; set; } private void ListBox_SelectionChanged(object sender,SelectionChangedEventArgs e) { ListBox control = (ListBox)sender; control.ScrollIntoView(control.SelectedItem); } 现在.如果我将AnimalsListBox.SelectedItem设置为当前不可见的项目,我希望它在视图中滚动.这是它变得棘手的地方,因为ListBox是组(IsGrouped属性为true),对ScrollIntoView的调用失败. System.Windows.Controls.ListBox通过反射器.注意在OnBringItemIntoView中的base.IsGrouping. public void ScrollIntoView(object item) { if (base.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { this.OnBringItemIntoView(item); } else { base.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,new DispatcherOperationCallback(this.OnBringItemIntoView),item); } } private object OnBringItemIntoView(object arg) { FrameworkElement element = base.ItemContainerGenerator.ContainerFromItem(arg) as FrameworkElement; if (element != null) { element.BringIntoView(); } else if (!base.IsGrouping && base.Items.Contains(arg)) { VirtualizingPanel itemsHost = base.ItemsHost as VirtualizingPanel; if (itemsHost != null) { itemsHost.BringIndexIntoView(base.Items.IndexOf(arg)); } } return null; } 问题 >任何人都可以解释为什么在使用分组时不起作用? > ItemContainerGenerator.ContainerFromItem始终返回null,即使状态表示已经生成了所有容器. >使用分组时如何实现滚动浏览? 解决方法
我找到了解决我的问题的办法.我确信我不是第一个打这个问题的人,所以我继续搜索StackOverflow的解决方案,而我在这个答案中偶然发现了David
about how ItemContainerGenerator works with a grouped list.
David的解决方案是延迟访问ItemContainerGenerator,直到渲染过程为止. 我已经实现了这个解决方案,稍后我会详细说明一些修改. private void ListBox_SelectionChanged(object sender,SelectionChangedEventArgs e) { ListBox control = (ListBox)sender; if (control.IsGrouping) { if (control.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) Dispatcher.BeginInvoke(DispatcherPriority.Render,new Action(DelayedBringIntoView)); else control.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; } else control.ScrollIntoView(control.SelectedItem); } private void ItemContainerGenerator_StatusChanged(object sender,EventArgs e) { if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) return; ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; Dispatcher.BeginInvoke(DispatcherPriority.Render,new Action(DelayedBringIntoView)); } private void DelayedBringIntoView() { var item = ItemContainerGenerator.ContainerFromItem(SelectedItem) as ListBoxItem; if (item != null) item.BringIntoView(); } 变化: >当IsGrouping为true时,仅使用ItemContainerGenerator方法,否则继续使用默认的ScrollIntoView.>检查ItemContainerGenerator是否准备就绪,如果是这样调度操作,否则监听ItemContainerGenerator状态以更改..这很重要,就好像它已经准备就绪,然后StatusChanged事件将永远不会触发. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |