Есть базовый класс Action обозначающий действие:
public class BaseAction
{
public string Name {get;set;}
}
И есть класс-наследник ExpanderAction, который обозначает череду таких действий:
public class ExpanderAction : BaseAction
{
public List<BaseAction> Actions {get;set;} = new List<BaseAction>();
}
Также существует коллекция элементов, которая привязана к ItemsControl:
public ObservableCollection<BaseAction> Actions {get;set;} = new ObservableCollection<BaseAction>();
Элементы коллекции могут быть представлены 2 видами:
кнопкой или другой коллекцией с элементами. Нужный шаблон выбирается через 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>
Проблема в том, что внутри ItemsControl, который лежит в шаблоне ExpanderActionTemplate элементы нужно отобразить также 2-я теми же самыми шаблонами.
Получается что-то вроде рекурсии.
Подскажите, как указать внутри ExpanderActionTemplate, что данные в ItemsControl должны отображаться его же шаблоном?
Update
Делаю так, но возникает ошибка на строке Second="{StaticResource Second}". Это происходит из-за того, что селектор объявлен раньше, чем шаблон данных Second.
<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>
У меня компилируется так:
<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>
(хотя и с предупреждением).
Если вы не хотите использовать DynamicResource, можно обойтись и без него за счёт 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"];
}
Можно найти родительский ItemsControl и забрать у него свойство ItemTemplateSelector:
<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>
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости