精简版
我想ListBox
在选择更改时将项目滚动到视图中.
长版
我有一个ListBox
与所述ItemsSource
绑定到一个CollectionViewSource
具有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>
Run Code Online (Sandbox Code Playgroud)
SelectionChanged
代码隐藏文件中有一个事件.
public List<Animal> Animals { get; set; }
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox control = (ListBox)sender;
control.ScrollIntoView(control.SelectedItem);
}
Run Code Online (Sandbox Code Playgroud)
现在.如果我将其设置AnimalsListBox.SelectedItem
为当前不可见的项目,我希望将其滚动到视图中.这就是它变得棘手的地方,因为ListBox
群组(IsGrouped
属性true
)是ScrollIntoView
失败的调用.
System.Windows.Controls.ListBox
通过反射器.注意base.IsGrouping
在OnBringItemIntoView
.
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;
}
Run Code Online (Sandbox Code Playgroud)
问题
ItemContainerGenerator.ContainerFromItem
始终返回null
,即使它已经产生的所有集装箱状态的状态.我找到了解决问题的方法.我确信我不是第一个遇到这个问题的人,所以我继续搜索StackOverflow的解决方案,我偶然发现了David 关于ItemContainerGenerator如何使用分组列表的答案.
大卫的解决办法是推迟访问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();
}
Run Code Online (Sandbox Code Playgroud)
变化:
ItemContainerGenerator
时,它的做法IsGrouping
是true
,否则继续使用默认ScrollIntoView
.ItemContainerGenerator
准备就绪,如果是,则调度操作,否则监听ItemContainerGenerator
状态改变.这很重要,好像它已准备就绪,然后StatusChanged
事件永远不会触发. 归档时间: |
|
查看次数: |
3301 次 |
最近记录: |