2011-05-13 114 views
1

我想动态添加一个按钮到网格内的WrapPanel,但WrapPanel引用(_innerPanel属性)在OnApplyTemplate被调用之前是无效的。强制OnApplyTemplate执行

这里是XMAL:

<s:MyGrid> 
    <WrapPanel x:Name="PART_InnerPanel"> 

    </WrapPanel> 
</s:MyGrid> 

MyGrid类:

public class MyGrid: Grid 
{ 
    WrapPanel _innerPanel; 

    public WrapPanel Panel 
    { 
     get{return _innerPanel;} 
    } 

    static MyGrid() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(MyGrid), new FrameworkPropertyMetadata(typeof(MyGrid))); 
    } 

    public override void OnApplyTemplate() 
    { 
     base.OnApplyTemplate(); 
     _innerPanel = Template.FindName("PART_InnerPanel", this) as WrapPanel; 
     if (_innerPanel == null) 
      throw new ResourceReferenceKeyNotFoundException("Invalid template"); 
    } 
} 

里面的代码:

MyGrid g = new MyGrid(); 
g.ApplyTemplate(); // <-- doesn't do anything 
g.UpdateLayout(); // <-- doesn't do anything 
if(g.Panel != null) // <-- it's NULL here as OnApplyTemplate hasn't get called 
{ 
    g.Panel.Children.Add(new Button()); 
} 

如何获得WrapPanel的参考,在XAML正确的定义行后

MyGrid g = new MyGrid(); 

或者任何解决方法或更好的方法来做到这一点?

回答

0

我使用的解决方案是通过在OnApplyTemplate覆盖中设置_innerPanel(和你一样)并且当我想使用它时总是检查它为空。

我从不向外公开该字段,因为不能保证模板设计人员将添加该控件。如果你像你这样做一个检查有一个保证,但你仍然依赖于WPF引擎加载模板。

只有在控件被构建后才能将控件添加到树中并找到模板。

所以我认为你不能有你所要求的。

0

您必须从ItemsControl派生控件才能将子项添加到您的控件中。暴露Panel并不是好的做法,而是在ItemsControl的Items属性内添加项目,ItemsControl为您提供了很多方法来自定义外观。

+0

我这样做只是为了显示我想要以最简单的方式做什么。它不需要在这里是WrapPanel,它可以是网格,画布,列表,树或任何其他容器。 – 2011-05-14 16:17:03