【问题标题】:Scroll a new item in a ItemsControl into view将 ItemsControl 中的新项目滚动到视图中
【发布时间】:2010-12-09 14:10:05
【问题描述】:

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

我认为ItemsControl 的大小在我查询大小时尚未更新,因为添加模型之前和之后的ActualHeight 是相同的。这段代码的效果是滚动到略高于新项目的位置。

我怎么知道新的ActualHeight 会是什么?

这是我的代码:

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

【问题讨论】:

    标签: wpf data-binding datatemplate itemscontrol


    【解决方案1】:

    我认为您需要在项目容器上调用 BringIntoView,而不是 ItemsControl 本身:

    var container = DocumentElements.ItemContainerGenerator.ContainerFromItem(model) as FrameworkElement;
    if (container != null)
        container.BringIntoView();
    

    编辑:实际上这不起作用,因为此时项目容器尚未生成...您可能可以处理ItemContainerGeneratorStatusChanged 事件。我尝试了以下代码:

    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;
        }
    }
    

    但是它也不起作用...由于某种原因,ContainerFromItem 在状态更改为ContainersGenerated 后仍然返回 null,我不知道为什么:S


    编辑:好的,我现在明白了...这是因为虚拟化:容器仅在需要显示时生成,因此不会为隐藏项生成容器。如果您为 ItemsControl (VirtualizingStackPanel.IsVirtualizing="False") 关闭虚拟化,则上述解决方案可以正常工作。

    【讨论】:

    • DocumentElements.ItemContainerGenerator.ContainerFromItem(model) 返回 null?我认为视图尚未更新为数据源中的新项目。
    • 啊,是的,我忘记了……但无论如何,如果容器不在 ItemsControl 中,你就不能滚动到它:S
    • 我尝试这样做但失败了。 ContainersGenerated 的事件不会在生成器上触发。
    猜你喜欢
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    相关资源
    最近更新 更多