ItemsControl: как использовать FindName в ItemsPanelTemplate для доступа к панели
<Style TargetType="{x:Type local:CustomItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter x:Name="PART_Presenter"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel x:Name="PART_StackPanel" IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
Попытка получить доступ к StackPanel для установки событий при изменении дочерних элементов.
[TemplatePartAttribute(Name = "PART_StackPanel", Type = typeof(StackPanel))]
[TemplatePartAttribute(Name = "PART_Presenter", Type = typeof(ItemsPresenter))]
public class CustomItemsControl: ItemsControl
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var presenter = (ItemsPresenter)this.Template.FindName("PART_Presenter", this);
var stackPanel = (StackPanel)this.ItemsPanel.FindName("PART_StackPanel",this);
}
}
Получите исключение, когда я пытаюсь найти StackPanel.
InvalidOperationException:
Эта операция действительна только для элементов, к которым применен этот шаблон.
Пожалуйста, сообщите, если есть способ найти TemplatePart внутри ItemsPanelTemplate. И когда я должен знать, когда применяется ItemsPanelTemplate?
3 ответа
Другой вариант - позвонить .ApplyTemplate()
на ItemsPresenter, пока еще в ItemControl's OnApplyTemplate
метод. Тогда призыв к .FindName
преуспеет.
[TemplatePartAttribute(Name = "PART_StackPanel", Type = typeof(StackPanel))]
[TemplatePartAttribute(Name = "PART_Presenter", Type = typeof(ItemsPresenter))]
public class CustomItemsControl : ItemsControl
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var presenter = (ItemsPresenter)this.Template.FindName("PART_Presenter", this);
presenter.ApplyTemplate();
var stackPanel = (StackPanel)this.ItemsPanel.FindName("PART_StackPanel", presenter);
}
}
Выяснилось, что событие Loaded было тем, которое нужно ожидать на ItemsPanelTemplate. Я могу найти StackPanel, используя имя TemplatePart. Спасибо Рику за предложение, что StackPanel должен быть найден в Presenter.
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
this.Loaded += new Accordion_Loaded;
}
void Accordion_Loaded(object sender, RoutedEventArgs e)
{
var presenter = (ItemsPresenter)this.Template.FindName("PART_Presenter", this);
var stackPanel = (StackPanel)this.ItemsPanel.FindName("PART_StackPanel", presenter);
}
FindName
Метод находит только имена в расширенном шаблоне и ItemsPanel
расширяется ItemsPresenter
, не ItemsControl
, В вашей ситуации "PART_StackPanel"
всегда будет дитя "PART_Presenter"
так что вы можете получить ссылку на это так:
var stackPanel = (StackPanel)VisualTreeHelper.GetChild(presenter, 0);