Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UserControl within a ControlTemplate

I have a ControlTemplate for a Telerik Tile and I am overriding like below:

<ControlTemplate TargetType="{x:Type ctrl:Tile}">
    <Border>  

        <local:UserControl>
            <ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
        </local:UserControl>
    </Border>
</ControlTemplate>

My user control looks like:

    <DockPanel>
        <!-- some content -->

        <ContentPresenter/>

    </DockPanel>

The ControlTemplate does not display the content of the UserControl.

If I change my control template to:

<ControlTemplate TargetType="{x:Type ctrl:Tile}">
    <Border>  
        <StackPanel>
            <local:UserControl/>

            <ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
       </StackPanel>
    </Border>
</ControlTemplate>

It will find the content and place it appropriately. It seems like the ControlTemplate cannot find the content once it's nested inside my UserControl. Is there anything I could be doing wrong?

Note that these ControlTemplate Items are appearing in an ItemsPresenter.

like image 743
Brian Triplett Avatar asked Mar 24 '23 11:03

Brian Triplett


1 Answers

You're treating the UserControl as if it is a basic ContentControl (like a Button) which is a little different than what it actually is. Using Button as an example, when you add a child (i.e. a TextBlock) into a Button element that's actually setting that TextBlock as the Button's Content property. The way it gets rendered is through the Button's ControlTemplate, which includes a ContentPresenter to inject Content into. The Visual Tree ends up like this:

<Button>
  -start Template
  <Border>
    <ContentPresenter>
      -start Content
      <TextBlock>

So far that's basically the model your code is following. The problem is that you're using a (still ContentControl derived) UserControl instead, which rather than using a ControlTemplate is most often defined with a XAML+code-behind model, where the XAML defines the Content of the UserControl. (It is possible to switch these models and template a UserControl or make a Button derived class with XAML+code-behind but not common)

If you want to both define the look of your UserControl in XAML as normal and still be able to inject other content you can add another DependencyProperty that mirrors the setup of the Content property and set your content to that. This approach is used with HeaderedContentControl derivatives (i.e. Expander) which essentially has 2 content properties, Content and Header. Using the new property would look like this:

<Border>  
    <local:UserControl>
      <local:UserControl.OtherContent>
          <ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
      </local:UserControl.OtherContent>
    </local:UserControl>
</Border>

And then inside the UserControl's XAML you need to explicitly set up the ContentPresenter Bindings (you only get them for free inside templates of ContentControls):

<DockPanel>
    <!-- some content -->

    <ContentPresenter Content="{Binding Path=OtherContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"/>
</DockPanel>

If you want a ContentTemplate, ContentTemplateSelector, or ContentStringFormat you'll also need to add properties and bindings for those.

like image 197
John Bowen Avatar answered Apr 03 '23 05:04

John Bowen