将ItemsControl中的新项滚动到视图中

8

我有一个ItemsControl,它通过数据绑定到一个ObservableCollection。我在代码后台中有这个方法,它将一个新的模型添加到列表中。我希望将新的项目(在列表底部)滚动到视图中。

我认为当我查询大小时,ItemsControl的大小还没有更新,因为添加模型之前和之后的ActualHeight是相同的。这段代码的效果是滚动到新项目上方略微的位置。

我如何知道新的ActualHeight将是多少?

以下是我的代码:

        ViewModel.CreateNewChapter();
        var height = DocumentElements.ActualHeight;
        var width = DocumentElements.ActualWidth;
        DocumentElements.BringIntoView(new Rect(0, height - 1, width, 1));
1个回答

7
我认为你需要在项容器上调用BringIntoView,而不是在ItemsControl本身上进行调用:
var container = DocumentElements.ItemContainerGenerator.ContainerFromItem(model) as FrameworkElement;
if (container != null)
    container.BringIntoView();

编辑:实际上这个方法不起作用,因为此时项容器还没有生成... 你可以尝试处理 ItemContainerGenerator StatusChanged 事件。我尝试了以下代码:
public static class ItemsControlExtensions
{
    public static void BringItemIntoView(this ItemsControl itemsControl, object item)
    {
        var generator = itemsControl.ItemContainerGenerator;

        if (!TryBringContainerIntoView(generator, item))
        {
            EventHandler handler = null;
            handler = (sender, e) =>
            {
                switch (generator.Status)
                {
                    case GeneratorStatus.ContainersGenerated:
                        TryBringContainerIntoView(generator, item);
                        break;
                    case GeneratorStatus.Error:
                        generator.StatusChanged -= handler;
                        break;
                    case GeneratorStatus.GeneratingContainers:
                        return;
                    case GeneratorStatus.NotStarted:
                        return;
                    default:
                        break;
                }
            };

            generator.StatusChanged += handler;
        }
    }

    private static bool TryBringContainerIntoView(ItemContainerGenerator generator, object item)
    {
        var container = generator.ContainerFromItem(item) as FrameworkElement;
        if (container != null)
        {
            container.BringIntoView();
            return true;
        }
        return false;
    }
}

然而,也不起作用...由于某种原因,即使状态更改为"ContainersGenerated","ContainerFromItem"仍然返回null,我不知道为什么:S
编辑:好的,我现在明白了...这是由于虚拟化:容器只有在需要显示时才生成,因此对于隐藏的项不会生成任何容器。如果您关闭ItemsControl的虚拟化(VirtualizingStackPanel.IsVirtualizing="False"),上面的解决方案就可以正常工作了。

DocumentElements.ItemContainerGenerator.ContainerFromItem(model) 返回 null 吗?我认为视图还没有更新到数据源中的新项目。 - Pieter Breed
啊,是的,我忘记了……但无论如何,如果容器还没有在ItemsControl中,你就不能滚动到它那里:S - Thomas Levesque
我尝试过这样做,但失败了。ContainersGenerated事件在生成器上没有触发。 - Pieter Breed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接