ItemsControl:如何在ItemsPanelTemplate中使用FindName来访问Panel

时间:2011-01-27 03:56:47

标签: c# wpf

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

  

此操作仅对已应用此模板的元素有效。

请告知是否有办法在ItemsPanelTemplate中找到TemplatePart。我什么时候应该知道什么时候应用ItemsPanelTemplate?

3 个答案:

答案 0 :(得分:5)

另一种选择是在ItemControl的.ApplyTemplate()方法中调用ItemsPresenter上的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);
        }
    }

答案 1 :(得分:1)

想出Loaded事件是在ItemsPanelTemplate上等待的事件。我能够使用TemplatePart名称找到StackPanel。感谢Rick建议在Presenter中找到StackPanel。

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

答案 2 :(得分:0)

FindName方法仅在已展开的模板中查找名称,并ItemsPanel展开ItemsPresenter,而不是ItemsControl。在您的情况下,"PART_StackPanel"将永远是"PART_Presenter"的孩子,因此您可以像这样获得对它的引用:

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