2010-07-21 17 views
13

Tengo una clase algo así como:¿Son posibles las plantillas de datos recursivas?

public class Section 
{ 
    private IEnumerable<Section> sections; 
    private IEnumerable<KeyValuePair<string, string>> attributes 

    public string Name {get;set;} 
    public IEnumerable<Section> Sections 
    { 
     get {return sections;} 
    } 
    public IEnumerable<KeyValuePair<string, string>> Attributes 
    { 
     get {return attributes;} 
    } 

    public Section(...) 
    { 
     //constructor logic 
    } 
} 

que está contenida en otra clase, vamos a llamarlo OtherClass por el bien de la discusión, que se envuelve alrededor de ella y que se usa en WPF en una ObjectDataProvider.

Como puede ver, una instancia de Section puede contener muchas otras instancias de Section.

¿Hay alguna manera en XAML para crear una plantilla que se ocupe de esta recursión?

Esto es lo que tengo hasta ahora:

<UserControl x:Class="OtherClassEditor" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:OtherClassNS="clr-namespace:NameSpace" 
    Height="300" Width="300"> 
    <UserControl.Resources> 
     <ObjectDataProvider ObjectType="{x:Type OtherClassNS:OtherClass}" x:Key="ViewModel" /> 
     <DataTemplate x:Key="listViewAttr"> 
      <WrapPanel> 
       <TextBlock Text="{Binding Path=Key}"></TextBlock><TextBlock Margin="0,0,4,0">: </TextBlock> 
       <TextBlock Text="{Binding Path=Value}"></TextBlock> 
      </WrapPanel> 
     </DataTemplate> 
     <DataTemplate x:Key="listViewSection"> 
      <StackPanel> 
       <WrapPanel Margin="0,0,0,8"> 
        <TextBlock Margin="0,0,4,0">Section:</TextBlock> 
        <TextBlock Text="{Binding Path=Name}"/> 
       </WrapPanel> 
      </StackPanel> 
     </DataTemplate> 
     <DataTemplate x:Key="listViewData"> 
      <StackPanel> 
       <WrapPanel Margin="0,0,0,8"> 
        <TextBlock Margin="0,0,4,0">Section: </TextBlock> 
        <TextBlock Text="{Binding Path=Name}"/> 
        <ListView DataContext="{Binding Path=Sections}" ItemTemplate="{StaticResource listViewSection}" ItemsSource="{Binding Sections}"> 
        </ListView> 
        <ListView DataContext="{Binding Path=Attributes}" ItemsSource="{Binding Attributes}" ItemTemplate="{StaticResource listViewAttr}"> 

        </ListView> 
       </WrapPanel> 
      </StackPanel>  
     </DataTemplate> 
    </UserControl.Resources> 
    <Grid> 
     <ListView DataContext="{StaticResource ViewModel}" ItemTemplate="{StaticResource listViewData}" ItemsSource="{Binding Sections}"> 
     </ListView> 
    </Grid> 
</UserControl> 

pero no puedo conseguir la recursividad, como DataTemplate sólo puede hacer referencia a uno que se declara antes de ella.

¿Se puede hacer esto en XAML? ¿Si es así, cómo? ¿Esto es algo que tendré que hacer en el código?

¿DataTemplates es aún el camino a seguir? ¿Hay una mejor manera de mostrar y editar esta información?

+3

¿Funciona esto si utiliza DynamicResource en lugar de StaticResource? Sería interesante si funciona, pero odiaría ver qué pasa si la plantilla causa una recursión infinita. –

+0

¡No había pensado en eso! Funciona, pero me gusta el aspecto de 'HierarchicalDataTemplate'. Parece más adecuado para el propósito. –

Respuesta

2

Tal vez estoy malinterpretando su situación, pero es HierarchicalDataTemplate lo que está buscando?

+0

Gracias por el consejo, estoy leyendo ahora. –

+0

HierarchicalDataTemplate solo funciona con TreeView y MenuItem. No sé por qué esta es la respuesta aceptada. –

22

En caso de que alguien necesita ver cómo hacer esto sin usar un HierarchicalDataTemplate:

<UserControl x:Class="OtherClassEditor" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:OtherClassNS="clr-namespace:NameSpace" 
    Height="300" Width="300"> 
    <UserControl.Resources> 
     <ObjectDataProvider ObjectType="{x:Type OtherClassNS:OtherClass}" x:Key="ViewModel" /> 
     <DataTemplate x:Key="listViewAttr"> 
      <WrapPanel> 
       <TextBlock Text="{Binding Path=Key}"></TextBlock> 
       <TextBlock Margin="0,0,4,0">: </TextBlock> 
       <TextBlock Text="{Binding Path=Value}"></TextBlock> 
      </WrapPanel> 
     </DataTemplate> 
     <DataTemplate x:Key="listViewData"> 
      <StackPanel> 
       <WrapPanel Margin="0,0,0,8"> 
        <TextBlock Margin="0,0,4,0">Section: </TextBlock> 
        <TextBlock Text="{Binding Path=Name}"/> 
       </WrapPanel> 
       <ListView ItemTemplate="{DynamicResource listViewData}" ItemsSource="{Binding Sections}" /> 
       <ListView ItemsSource="{Binding Attributes}" ItemTemplate="{StaticResource listViewAttr}" /> 
      </StackPanel>  
     </DataTemplate> 
    </UserControl.Resources> 
    <Grid> 
     <ListView DataContext="{StaticResource ViewModel}" ItemTemplate="{DynamicResource listViewData}" ItemsSource="{Binding Sections}"> 
     </ListView> 
    </Grid> 
</UserControl> 

Esto me hace básicamente lo que quiero.

El cambio principal es como lo sugirió Dan Bryant: cambiar el ItemTemplate para usar un recurso dinámico en lugar de estático para el objeto recursivo (Section).

Cuestiones relacionadas