为什么ItemContainerGenerator返回null?

时间:2010-07-20 10:38:13

标签: wpf

我有一个ListBox,我需要将其ControlTemplate设置为Virtualizing WrapPanel,这是一个使用如下样式扩展VirtualizingPanel的类:

<Style TargetType="{x:Type ListBox}" x:Key="PhotoListBoxStyle">
                <Setter Property="Foreground" Value="White" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate  TargetType="{x:Type ListBox}" >
                            <s:VirtualizingVerticalWrapPanel>
                            </s:VirtualizingVerticalWrapPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

现在,在下面虚拟化WrapPanel的私有方法中,我尝试访问this.ItemContainerGenerator,但是我得到null值,任何想法是什么问题?

private void RealizeFirstItem()
{
    IItemContainerGenerator generator = this.ItemContainerGenerator;
    GeneratorPosition pos = generator.GeneratorPositionFromIndex(0);

    using (generator.StartAt(pos, GeneratorDirection.Forward))
    {
        UIElement element = generator.GenerateNext() as UIElement;

         generator.PrepareItemContainer(element);

                    this.AddInternalChild(element);
    }
 }

5 个答案:

答案 0 :(得分:7)

我认为我遇到了类似的问题,这有助于:

var necessaryChidrenTouch = this.Children;
IItemContainerGenerator generator = this.ItemContainerGenerator;

...由于某种原因,您必须“触摸”子集合才能使ItemContainerGenerator正确初始化。

答案 1 :(得分:2)

对于Windows 8.1 Metro应用程序,ItemContainerGenerator已被删除,并将返回null。新的Apis:

ItemsControl.ItemContainerGenerator.ItemFromContainer = ItemsControl.ItemFromContainer

ItemsControl.ItemContainerGenerator.ContainerFromItem = ItemsControl.ContainerFromItem

ItemsControl.ItemContainerGenerator.IndexFromContainer = ItemsControl.IndexFromContainer

ItemsControl.ItemContainerGenerator.ContainerFromIndex = ItemsControl.ContainerFromIndex

http://msdn.microsoft.com/en-us/library/windows/apps/dn376326.aspx

答案 2 :(得分:0)

Falck大多是正确的。实际上,您需要引用虚拟化堆栈面板的“InternalChildren”。此属性的反编译代码为:

    protected internal UIElementCollection InternalChildren
    {
        get
        {
            this.VerifyBoundState();
            if (this.IsItemsHost)
            {
                this.EnsureGenerator();
            }
            else if (this._uiElementCollection == null)
            {
                this.EnsureEmptyChildren(this);
            }
            return this._uiElementCollection;
        }
    }

'EnsureGenerator'负责确保发电机可用。非常差的'及时'设计,IMO。

答案 3 :(得分:0)

很可能这是与虚拟化相关的问题,因此仅为当前可见的项目生成ListBoxItem容器(例如https://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel(v=vs.110).aspx#Anchor_9

我建议切换到ListView而不是ListBox - 它继承自ListBox,它支持ScrollIntoView()方法,您可以利用它来控制虚拟化;

targetListView.ScrollIntoView(itemVM);
DoEvents();
ListViewItem itemContainer = targetListView.ItemContainerGenerator.ContainerFromItem(itemVM) as ListViewItem;

(上面的示例还使用了此处详细说明的DoEvents()静态方法; WPF how to wait for binding update to occur before processing more code?

ListBoxListView控件(What is The difference between ListBox and ListView)之间存在一些其他细微差别 - 这不一定会影响您的使用案例。

答案 4 :(得分:-1)

这是因为您更改了列表框的模板,而您应该刚刚更改了ItemsPanel:

    <ListBox>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <s:VirtualizingVerticalWrapPanel />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>