Force OnApplyTemplate to execute
I'm trying to add a button dynamically to a WrapPanel which is inside the Grid but the WrapPanel reference (_innerPanel property) is not valid until the OnApplyTemplate get called.
Here is the XMAL :
<s:MyGrid>
<WrapPanel x:Name="PART_InnerPanel">
</WrapPanel>
</s:MyGrid>
MyGrid class:
public class MyGrid: Grid
{
Wrap开发者_JAVA百科Panel _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");
}
}
Inside the code:
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());
}
How to get the reference of the WrapPanel that defined in XAML right after the line
MyGrid g = new MyGrid();
Or any workaround or better way to do this?
The solution that I use is by setting the _innerPanel in the OnApplyTemplate override (like you do) and always checking it for null when I want to use it.
I never expose the field outward because there is no guarantee that a template designer will add the control. If you do a check like you do there is a guarantee but still you are dependent on the WPF engine to load the template.
It is only AFTER the control has been constructed that the control can be added to the tree and the template can be found.
So I think you can't have what you ask for.
You have to derive your control from ItemsControl in order to add children to your control. It is not good practice to expose Panel instead add items inside items property of ItemsControl and ItemsControl gives you many ways to customize the look and feel.
精彩评论