2010-07-21 4 views
13

У меня есть класс что-то вроде:Возможны ли рекурсивные DataTemplates?

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

который содержится в другом классе, позволяет называть его OtherClass ради аргумента, который оборачивается вокруг него и используется в WPF в ObjectDataProvider.

Как вы можете видеть, экземпляр Section может содержать много других экземпляров Section.

Есть ли способ в XAML создать шаблон, который имеет дело с этой рекурсией?

Это то, что я получил до сих пор:

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

Но я не могу получить рекурсию, как DataTemplate может ссылаться только на тот, который объявляется перед ним.

Можно ли это сделать в XAML? Если да, то как? Это что-то, что мне нужно сделать в коде?

Есть DataTemplates, даже способ пойти? Есть ли лучший способ отображать и редактировать эти данные?

+3

Это работает, если вы используете DynamicResource вместо StaticResource? Было бы интересно, если это сработает, но мне не хотелось бы видеть, что произойдет, если шаблон вызывает бесконечную рекурсию. –

+0

Я не думал об этом! Он работает, но мне нравится внешний вид «HierarchicalDataTemplate». Это кажется более подходящим для цели. –

ответ

2

Возможно, я не понимаю ваш сценарий, но HierarchicalDataTemplate что вы ищете?

+0

Спасибо за подсказку, сейчас я читаю об этом. –

+0

HierarchicalDataTemplate работает только с TreeView и MenuItem. Я не знаю, почему это принятый ответ. –

22

В случае, если кто хочет видеть, как сделать это без использования 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> 

Это заставляет меня в основном то, что я хочу.

Главное изменение, как предложил Дэн Брайант: изменить ItemTemplate на использование динамического, а не статического ресурса для рекурсивного объекта (Section).

Смежные вопросы