How to access a named element in a control that in

2019-02-24 23:32发布

问题:

Hello this is similar to How to access a named element of a derived user control in silverlight? with the difference is inheriting from a templated control, not a user control.

I have a templated control called MyBaseControl

Xaml:-

<Style TargetType="Problemo:MyBaseControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Problemo:MyBaseControl">
                    <Grid x:Name="LayoutRoot" Background="White">
                        <Border Name="HeaderControl" Background="Red" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Code:-

 public class MyBaseControl : Control
    {
        public UIElement Header { get; set; }

        public MyBaseControl()
        {   
            DefaultStyleKey = typeof(MyBaseControl);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            var headerControl = GetTemplateChild("HeaderControl") as Border;

            if (headerControl != null)
                headerControl.Child = Header;

        }
    }

I have another control called myControl which inherits from MyBaseControl Control

Xaml:-

<me:MyBaseControl x:Class="Problemo.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:me="clr-namespace:Problemo" 
    d:DesignHeight="300" d:DesignWidth="400">
    <me:MyBaseControl.Header>
        <TextBlock Name="xxx" />
    </me:MyBaseControl.Header> 
</me:MyBaseControl>

Code:-

public partial class MyControl : MyBaseControl
{
    public string Text { get; set; }

    public MyControl(string text)
    {
        InitializeComponent();
        Text = text;
        Loaded += MyControl_Loaded;
    }

    void MyControl_Loaded(object sender, RoutedEventArgs e)
    {
        base.ApplyTemplate();
        xxx.Text = Text;
    }
}

The issue is xxx is null. How do I access the xxx control in the code behind ?

回答1:

When you access the HeaderControl, that is being pulled from the ControlTemplate. The elements in the ControlTemplate are created and added as visual descendants of the control. Then the OnApplyTemplate method is called and you can access them via their name.

In the second case, you are specifically assigning a single element to the Header property. There is no way to get a "named" element in this case, as the header is being explicitly set.

You could cast the Header property directly, if you know that it's going to be a TextBlock, like so:

TextBlock tb = this.Header as TextBlock;
if (tb != null)
    tb.Text = Text;

Otherwise, you could bind the TextBlock to your Text property in your XAML, like so:

<me:MyBaseControl.Header>
<TextBlock Name="xxx" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type me:MyControl}}, Path=Text}" />
</me:MyBaseControl.Header>

The latter method of binding is the better way to go, since you are not tied to a given control (i.e. TextBlock).