2012-07-16 15 views
11

Tengo un panel personalizado donde declaré una propiedad personalizada para mantener el contenido (no quiero usar a los niños para el contenido):ItemsPanelTemplate en XAML ignora [ContentProperty] atributo

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

Esto funciona perfectamente cuando se usa de esta manera:

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

Pero cuando quiero utilizar el panel como un ItemsPanelTemplate dentro ItemsControl, el atributo ContentProperty se ignora y se añade todo a los niños colección, no el PanelContent colección:

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

Ésta no es la forma en que debería funcionar. De acuerdo con documentation:

Un elemento de elemento ItemsPanelTemplate debe contener exactamente una clase derivada de FrameworkElement que sirve como elemento raíz para los elementos. En la mayoría de los casos, esta es una clase derivada del Panel. La plantilla expandida sirve como padre para los elementos realizados y generalmente hay más de un elemento. Por lo tanto, la propiedad de contenido XAML del elemento raíz deseado de una ElementsPanelTemplate debe admitir una colección, como lo hace Panel.Children.

Respuesta

2

método GenerateChildren del Grupo Especial, que es responsable de esta tarea se ve (como se ve en ILSpy) como

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

Como se puede ver, que siempre se suma a this._uiElementCollection, que es el campo de copias de los Niños propiedad.

0

Porque ItemsPanelTemplate es utilizado por ItemsControl para crear y usar el Panel y no es XAML el que hace nada. ItemsControl simplemente llamará a Panel.Children.Add sin importar en qué ContentProperty esté configurado.

Se supone que el panel solo distribuye los elementos y nunca los estilo. Entonces, todo lo que debe hacer es omitir los métodos Organizar y Medir. Todos los paneles solo hacen eso.

Para el estilo y cualquier otra lógica debe usar otro enfoque.

+0

Eso no es del todo cierto. Eche un vistazo al panel 'RichTextColums' que forma parte de todas las aplicaciones de Metro que crea en Visual Studio. –

+0

El panel solo cambia el diseño, RichTextColumns admite el diseño de sus elementos secundarios, lo hace paginación, diseños de columna. Y todo lo que hace es Medir y organizar sus hijos. Buscaré en el código fuente a través del reflector, pero estoy bastante seguro, los paneles no agregan/cambian de estilos. Pueden anular los recursos de estilo, pero la fuente del Panel no contendrá ningún código de estilo. –

+0

De hecho, y eso es exactamente lo que quiero lograr. Nunca dije nada sobre el estilo. Solo quiero usar una propiedad diferente para el contenido (no 'Children').Lamentablemente, el nombre de propiedad especificado no es respetado por 'ItemsControl'. –

1

Creo que ItemsPanelTemplate solo puede tomar Panel.Children como objetivo para los elementos de diseño. De hecho, si usted deriva su CustomPanel de, por ejemplo, ContentControl, encontrará siguiente mensaje de excepción en aplicación de estilo de Metro:

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

La documentación se enlazó podría ser un error de documentación que fue copiado de vez WPF, cuando aún puede insertar visuales programáticamente en el árbol visual. En la aplicación Metro, ya no hay forma de poner tu propia lista de UIElements en el árbol visual sin usar Panel.Children.