2010-07-21 15 views
13

Ho una classe qualcosa di simile:Sono possibili DataTemplates ricorsivi?

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

che è contenuta in un'altra classe, consente di chiamare OtherClass per amor di discussione, che si avvolge attorno ad esso ed è utilizzato in WPF in un ObjectDataProvider.

Come si può vedere, un'istanza di Section può contenere molte altre istanze di Section.

C'è un modo in XAML per creare un modello che si occupa di questa ricorsione?

Questo è quello che ho finora:

<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> 

ma non riesco a ottenere la ricorsione, come DataTemplate può fare riferimento solo uno che è dichiarato prima.

È possibile farlo in XAML? Se é cosi, come? È qualcosa che dovrò fare nel codice dietro?

Are DataTemplates anche la strada da percorrere? C'è un modo migliore per visualizzare e modificare questi dati?

+3

Funziona se si utilizza DynamicResource anziché StaticResource? Sarebbe interessante se funzionasse, ma odio vedere cosa succede se il modello causa una ricorsione infinita. –

+0

Non ci avevo pensato! Funziona, ma mi piace l'aspetto di 'HierarchicalDataTemplate'. Sembra più adatto allo scopo. –

risposta

2

Forse sto fraintendendo il tuo scenario, ma è HierarchicalDataTemplate quello che stai cercando?

+0

Grazie per il suggerimento, sto leggendo su di esso ora. –

+0

HierarchicalDataTemplate funziona solo con TreeView e MenuItem. Non so perché questa è la risposta accettata. –

22

Nel caso qualcuno ha bisogno di vedere come fare questo senza usare 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> 

Questo mi fa sostanzialmente quello che voglio.

Il cambiamento principale è quello suggerito da Dan Bryant: cambiare lo ItemTemplate per utilizzare una risorsa dinamica piuttosto che statica per l'oggetto ricorsivo (Section).