为什么ItemContainerGenerator返回null?

问题描述:

我有一个列表框,我需要它的控件模板设置为虚拟WrapPanel这是一个扩展VirtualizingPanel,使用样式,看起来像这样一类:为什么ItemContainerGenerator返回null?

<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,但我得到空值,任何想法有什么问题?

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); 
    } 
} 
+0

“this.ItemContainerGenerator”是否意味着Listbox? – Ragunathan 2010-07-20 12:02:16

+0

这是指Virtualizing WrapPanel,虚拟化WrapPanel用在ListBox的ControlTemplate中 – simo 2010-07-22 06:52:37

我想我也有类似的问题,这有助于:

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

...由于某种原因,你必须以“触摸”孩子们收集了ItemContainerGenerator正确初始化。

+0

不知道你为什么被低估,按照我的经验你是绝对正确的。这是一个早在5年前由Avalon团队成员注意到的错误。 – Jordan0Day 2011-06-08 16:09:51

+0

完美,谢谢! – Andy 2013-03-04 11:47:53

这是因为你改变了ListBox的模板,而ü应该有只是改变了ItemsPanel:

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

法尔克大多是正确的。实际上,你需要引用虚拟化堆栈面板的'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)非常糟糕的“及时”设计。

对于Windows 8.1 Metro应用程序,ItemContainerGenerator被取消并返回null。新的API:

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

+0

非常感谢先生 – FatemehEbrahimiNik 2016-05-21 07:36:14

很可能这是一个虚拟化相关问题,所以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)差异 - 这不应该基本上影响你的用例。