2011-01-27 3 views
2
<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 для установки событий при изменении детей.ItemsControl: Как использовать FindName в ItemsPanelTemplate для доступа к панели

[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. И когда я должен знать, когда применяется ItemPanelTemplate?

+0

Какие события вам необходимо подписаться? –

ответ

0

Метод FindName только находит имена в шаблоне, который был расширен, а ItemsPanel расширена ItemsPresenter, а не ItemsControl. В вашей ситуации "PART_StackPanel" всегда будет дитя "PART_Presenter", так что вы можете получить ссылку на него, как это:

var stackPanel = (StackPanel)VisualTreeHelper.GetChild(presenter, 0); 
+0

Все еще получаю ArgumentOutOfRangeException на этой строке. Указанный индекс находится за пределами допустимого диапазона, или дочерний элемент индекса имеет значение NULL. Не вызывайте этот метод, если VisualChildrenCount возвращает ноль, указав, что у Visual нет дочерних элементов. Имя параметра: индекс Фактическое значение было 0. Также неясно, какие расширенные средства при обращении к шаблону. Спасибо за помощь. Есть ли еще один момент, когда я могу ожидать, что PART_StackPanel будет добавлен в презентацию? – Case

+0

Вы можете переместить свой 'StackPanel' в' ControlTemplate' и не использовать 'ItemsPresenter'. Или вы можете искать 'StackPanel' в событии' Loaded' 'ItemsPresenter'. Расширенные средства, которые применяют шаблон. Элемент 'ItemsControl' не применяет шаблон' ItemsPanel'. –

1

Разобрался, что Loaded событие было один ждать на ItemsPanelTemplate. Я могу найти StackPanel с помощью TemplatePart Name. Спасибо Рику за то, что он предложил 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); 
    } 
4

Другой вариант заключается в вызове .ApplyTemplate() на ItemsPresenter еще в OnApplyTemplate методе ItemControl в. Тогда вызов .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); 
     } 
    } 
+0

Отличный ответ! –

+0

Отлично. Это работает. –

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