There is an Action base class denoting an action:

 public class BaseAction { public string Name {get;set;} } 

And there is a class-successor ExpanderAction , which denotes a series of such actions:

 public class ExpanderAction : BaseAction { public List<BaseAction> Actions {get;set;} = new List<BaseAction>(); } 

There is also a collection of items that is bound to an ItemsControl :

 public ObservableCollection<BaseAction> Actions {get;set;} = new ObservableCollection<BaseAction>(); 

Elements of the collection can be represented by 2 types: a button or another collection with elements. The desired template is selected via ItemTemplateSelector .

 <DataTemplate x:Key="BaseActionTemplate" DataType="{x:Type actions:BaseAction}"> <Button Content="{Binding Name}" /> </DataTemplate> <DataTemplate x:Key="ExpanderActionTemplate" DataType="{x:Type actions:ExpanderAction}"> <ItemsControl ItemsSource="{Binding Actions}" /> </DataTemplate> 

The problem is that inside the ItemsControl , which lies in the ExpanderActionTemplate template, the elements need to be displayed also by the 2nd same templates. It turns out something like a recursion.

Tell me how to indicate inside the ExpanderActionTemplate that the data in ItemsControl should be displayed by its own template?


Update

I do this, but an error occurs on the line Second="{StaticResource Second}" . This is due to the fact that the selector is declared earlier than the Second data template.

 <Window.Resources> <DataTemplate x:Key="First"> <Button Content="{Binding Name}" /> </DataTemplate> <local:Selector x:Key="Selector" First="{StaticResource First}" Second="{StaticResource Second}"/> <DataTemplate x:Key="Second"> <ItemsControl ItemTemplateSelector="{StaticResource Selector}" ItemsSource="{Binding Path=ChildActions}"/> </DataTemplate> </Window.Resources> <StackPanel> <ItemsControl ItemsSource="{Binding Actions}" ItemTemplateSelector="{StaticResource Selector}" /> </StackPanel> 
  • one
    Perhaps you need essentially a HierarchicalDataTemplate . - VladD
  • @VladD, As far as I understand the HierarchicalDataTemplate you can normally use only c TreeView . If to use with ItemsControl , then child elements are not displayed. - trydex
  • And how do you connect the ItemTemplateSelector ? Give more code. - VladD
  • And what does “the same two patterns” mean? Why it is impossible to register the same ItemTemplateSelector inside the ExpanderActionTemplate in ItemsControl ? - VladD
  • one
    Wrote the answer, try it. If that doesn't work, there are other options. - VladD

2 answers 2

I compile this way:

 <Window.Resources> <DataTemplate x:Key="First"> <Button Content="{Binding Name}" /> </DataTemplate> <DataTemplate x:Key="Second"> <ItemsControl ItemTemplateSelector="{DynamicResource Selector}" ItemsSource="{Binding Path=ChildActions}"/> </DataTemplate> <local:Selector x:Key="Selector" First="{StaticResource First}" Second="{StaticResource Second}"/> </Window.Resources> 

(albeit with a warning).


If you do not want to use DynamicResource , you can do without it due to the code-behind:

 <Window.Resources> <local:Selector x:Key="Selector"/> <DataTemplate x:Key="First"> <Button Content="{Binding Name}" /> </DataTemplate> <DataTemplate x:Key="Second"> <ItemsControl ItemTemplateSelector="{StaticResource Selector}" ItemsSource="{Binding Path=ChildActions}"/> </DataTemplate> </Window.Resources> 
 public MainWindow() { InitializeComponent(); // обязательно после InitializeComponent var selector = (Selector)Resources["Selector"]; selector.First = (DataTemplate)Resources["First"]; selector.Second = (DataTemplate)Resources["Second"]; } 
  • It works, thanks! Can you explain why everything is fine with DynamicResource , unlike StaticResource and for what reasons can I not want to use it? - trydex
  • one
    @maxwell: Well, StaticResource inserts a link at compile time, and requires that the name be defined in the file before the line where it is used. And you must have someone from Second and Selector first, and he will not be able to refer to the other. - VladD
  • one
    @maxwell: I put the DynamicResource in Second , not in the Selector , because ItemTemplateSelector is the dependency property in it, and I don’t know what the Second in the Selector and how the DynamicResource in case of a non-dependency property. - VladD
  • one
    @maxwell: DynamicResource substituted (as opposed to StaticResource ) at runtime, so it doesn’t care what it is and in what order. - VladD
  • one
    @maxwell: Please! Glad it helped! - VladD

You can find the parent ItemsControl and take the ItemTemplateSelector property from it:

 <DataTemplate x:Key="ExpanderActionTemplate" DataType="{x:Type actions:ExpanderAction}"> <ItemsControl ItemsSource="{Binding Actions}" ItemTemplateSelector="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=ItemTemplateSelector}"/> </DataTemplate>