XAML中的ItemsPanelTemplate忽略[ContentProperty]属性

时间:2012-07-16 09:28:04

标签: c# xaml windows-8 microsoft-metro

我有一个自定义Panel,我在其中声明了一个自定义属性来保存内容(我不想使用Children作为内容):

[ContentProperty(Name = "PanelContent")]
public class CustomPanel : Panel
{
    public static readonly DependencyProperty PanelContentProperty =
       DependencyProperty.Register("PanelContent", 
       typeof(Collection<UIElement>), typeof(CustomPanel), 
       new PropertyMetadata(new Collection<UIElement>(), null));

    public Collection<UIElement> PanelContent
    {
        get
        {
            return (Collection<UIElement>)GetValue(PanelContentProperty);
        }
    }
}

这样使用时效果非常好:

<CustomPanel>
   <TextBlock>A</TextBlock>
   <TextBlock>B</TextBlock>
</CustomPanel>

但是当我想在ItemsControl中使用面板作为ItemsPanelTemplate时,ContentProperty属性将被忽略并将所有内容添加到 Children 集合,而不是 PanelContent 集合:< / p>

<ItemsControl ItemTemplate="{StaticResource ReviewTemplate}" ItemsSource="{Binding Reviews}">
   <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
         <CustomPanel></CustomPanel>
      </ItemsPanelTemplate>
   </ItemsControl.ItemsPanel>
</ItemsControl>

这不是它应该如何运作的。根据{{​​3}}:

ItemsPanelTemplate对象元素应该只包含一个FrameworkElement派生类,该类用作项的根元素。在大多数情况下,这是一个Panel派生类。扩展模板用作已实现项目的父项,并且通常存在多个项目。因此,ItemsPanelTemplate的预期根元素的XAML内容属性应该支持集合,如Panel.Children那样。

3 个答案:

答案 0 :(得分:2)

Panel的GenerateChildren方法,负责此任务的外观(如ILSpy所示),如

internal virtual void GenerateChildren()
{
    IItemContainerGenerator itemContainerGenerator = this._itemContainerGenerator;
    if (itemContainerGenerator != null)
    {
        using (itemContainerGenerator.StartAt(new GeneratorPosition(-1, 0), GeneratorDirection.Forward))
        {
            UIElement uIElement;
            while ((uIElement = (itemContainerGenerator.GenerateNext() as UIElement)) != null)
            {
                this._uiElementCollection.AddInternal(uIElement);
                itemContainerGenerator.PrepareItemContainer(uIElement);
            }
        }
    }
}

如您所见,它总是添加到this._uiElementCollection,这是支持Children属性的字段。

答案 1 :(得分:1)

我认为ItemsPanelTemplate只能将Panel.Children作为布局项目的目标。事实上,如果您从ContentControl派生CustomPanel,您将在metro风格应用程序中找到以下异常消息:

Exception: The ItemsControl.ItemsPanelTemplate must have a derivative of Panel as the root element.

您链接的文档可能是从WPF时间复制的文档错误,此时您仍然可以通过编程方式将可视化插入到可视树中。在Metro应用程序中,不再使用Panel.Children将您自己的UIElements列表放入可视树中。

答案 2 :(得分:0)

因为ItemsControl使用ItemsPanelTemplate来创建和使用Panel,而不是XAML做任何事情。无论ContentProperty设置为什么,ItemsControl都会调用Panel.Children.Add。

Panel应该只布置子项,而不是它们的样式。所以你必须做的只是覆盖排列和测量方法。所有面板都是这样做的。

对于样式和任何其他逻辑,您必须使用其他方法。